diff --git a/Build/build.ps1 b/Build/build.ps1 index 37746543f..da53db98b 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -1,7 +1,7 @@ properties { - $zipFileName = "Json120r2.zip" - $majorVersion = "12.0" - $majorWithReleaseVersion = "12.0.2" + $zipFileName = "Json130r3.zip" + $majorVersion = "13.0" + $majorWithReleaseVersion = "13.0.2" $nugetPrerelease = $null $version = GetVersion $majorWithReleaseVersion $packageId = "Newtonsoft.Json" @@ -12,9 +12,11 @@ $msbuildVerbosity = 'minimal' $treatWarningsAsErrors = $false $workingName = if ($workingName) {$workingName} else {"Working"} - $netCliChannel = "2.0" - $netCliVersion = "2.2.105" + $assemblyVersion = if ($assemblyVersion) {$assemblyVersion} else {$majorVersion + '.0.0'} + $netCliChannel = "Current" + $netCliVersion = "6.0.400" $nugetUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" + $ensureNetCliSdk = $true $baseDir = resolve-path .. $buildDir = "$baseDir\Build" @@ -30,15 +32,14 @@ $nunitConsolePath = "$buildDir\Temp\NUnit.ConsoleRunner.$nunitConsoleVersion" $builds = @( - @{Framework = "netstandard2.0"; TestsFunction = "NetCliTests"; TestFramework = "netcoreapp2.2"; Enabled=$true}, - @{Framework = "netstandard1.3"; TestsFunction = "NetCliTests"; TestFramework = "netcoreapp1.1"; Enabled=$true}, - @{Framework = "netstandard1.0"; TestsFunction = "NetCliTests"; TestFramework = "netcoreapp1.0"; Enabled=$true}, + @{Framework = "net6.0"; TestsFunction = "NetCliTests"; TestFramework = "net6.0"; Enabled=$true}, + @{Framework = "netstandard2.0"; TestsFunction = "NetCliTests"; TestFramework = "net5.0"; Enabled=$true}, + @{Framework = "netstandard1.3"; TestsFunction = "NetCliTests"; TestFramework = "netcoreapp3.1"; Enabled=$true}, + @{Framework = "netstandard1.0"; TestsFunction = "NetCliTests"; TestFramework = "netcoreapp2.1"; Enabled=$true}, @{Framework = "net45"; TestsFunction = "NUnitTests"; TestFramework = "net46"; NUnitFramework="net-4.0"; Enabled=$true}, @{Framework = "net40"; TestsFunction = "NUnitTests"; NUnitFramework="net-4.0"; Enabled=$true}, @{Framework = "net35"; TestsFunction = "NUnitTests"; NUnitFramework="net-2.0"; Enabled=$true}, - @{Framework = "net20"; TestsFunction = "NUnitTests"; NUnitFramework="net-2.0"; Enabled=$true}, - @{Framework = "portable-net45+win8+wpa81+wp8"; TestsFunction = "NUnitTests"; TestFramework = "net452"; NUnitFramework="net-4.0"; Enabled=$true}, - @{Framework = "portable-net40+win8+wpa81+wp8+sl5"; TestsFunction = "NUnitTests"; TestFramework = "net451"; NUnitFramework="net-4.0"; Enabled=$true} + @{Framework = "net20"; TestsFunction = "NUnitTests"; NUnitFramework="net-2.0"; Enabled=$true} ) } @@ -70,7 +71,10 @@ task Build -depends Clean { mkdir "$buildDir\Temp" -Force - EnsureDotNetCli + if ($ensureNetCliSdk) + { + EnsureDotNetCli + } EnsureNuGetExists EnsureNuGetPackage "vswhere" $vswherePath $vswhereVersion EnsureNuGetPackage "NUnit.ConsoleRunner" $nunitConsolePath $nunitConsoleVersion @@ -154,11 +158,9 @@ function NetCliBuild() exec { & $script:msBuildPath "/t:restore" "/v:$msbuildVerbosity" "/p:Configuration=Release" "/p:LibraryFrameworks=`"$libraryFrameworks`"" "/p:TestFrameworks=`"$testFrameworks`"" "/m" $projectPath | Out-Default } "Error restoring $projectPath" - Write-Host -ForegroundColor Green "Building $libraryFrameworks in $projectPath" + Write-Host -ForegroundColor Green "Building $libraryFrameworks $assemblyVersion in $projectPath" Write-Host - $assemblyVersion = $majorVersion + '.0.0' - exec { & $script:msBuildPath "/t:build" "/v:$msbuildVerbosity" $projectPath "/p:Configuration=Release" "/p:LibraryFrameworks=`"$libraryFrameworks`"" "/p:TestFrameworks=`"$testFrameworks`"" "/p:AssemblyOriginatorKeyFile=$signKeyPath" "/p:SignAssembly=$signAssemblies" "/p:TreatWarningsAsErrors=$treatWarningsAsErrors" "/p:AdditionalConstants=$additionalConstants" "/p:GeneratePackageOnBuild=$buildNuGet" "/p:ContinuousIntegrationBuild=true" "/p:PackageId=$packageId" "/p:VersionPrefix=$majorWithReleaseVersion" "/p:VersionSuffix=$nugetPrerelease" "/p:AssemblyVersion=$assemblyVersion" "/p:FileVersion=$version" "/m" } } @@ -173,6 +175,8 @@ function EnsureDotnetCli() -OutFile "$buildDir\Temp\dotnet-install.ps1" exec { & $buildDir\Temp\dotnet-install.ps1 -Channel $netCliChannel -Version $netCliVersion | Out-Default } + exec { & $buildDir\Temp\dotnet-install.ps1 -Channel $netCliChannel -Version '3.1.402' | Out-Default } + exec { & $buildDir\Temp\dotnet-install.ps1 -Channel $netCliChannel -Version '2.1.811' | Out-Default } } function EnsureNuGetExists() @@ -323,4 +327,4 @@ function Execute-Command($command) { $currentRetry = $currentRetry + 1 } } while (!$success) -} \ No newline at end of file +} diff --git a/Build/version.json b/Build/version.json index b92f445b7..7e0f6ad33 100644 --- a/Build/version.json +++ b/Build/version.json @@ -1,5 +1,6 @@ { - "Major": 12, + "Major": 13, "Release": 2, - "Prerelease": null + "Prerelease": null, + "Assembly": null } \ No newline at end of file diff --git a/Doc/Samples/Serializer/NullValueHandlingIgnore.aml b/Doc/Samples/Serializer/NullValueHandlingIgnore.aml index afec219a3..b502d90dd 100644 --- a/Doc/Samples/Serializer/NullValueHandlingIgnore.aml +++ b/Doc/Samples/Serializer/NullValueHandlingIgnore.aml @@ -3,7 +3,7 @@ This sample serializes an object to JSON with T:Newtonsoft.Json.NullValueHandling - set to Ignore so that properties with a default value aren't included in the JSON result. + set to Ignore so that properties with a default value of null aren't included in the JSON result.
Sample @@ -13,4 +13,4 @@
- \ No newline at end of file + diff --git a/Doc/Samples/Serializer/SerializeTypeNameHandling.aml b/Doc/Samples/Serializer/SerializeTypeNameHandling.aml index 79eda1e9f..f34241659 100644 --- a/Doc/Samples/Serializer/SerializeTypeNameHandling.aml +++ b/Doc/Samples/Serializer/SerializeTypeNameHandling.aml @@ -3,7 +3,7 @@ This sample uses the T:Newtonsoft.Json.TypeNameHandling - setting to include type information when serializing JSON and read type information so that the create types are created when deserializing JSON. + setting to include type information when serializing JSON and read type information so that the correct types are created when deserializing JSON.
Sample @@ -13,4 +13,4 @@
- \ No newline at end of file + diff --git a/Doc/SelectToken.aml b/Doc/SelectToken.aml index 9b8ce1672..03299183c 100644 --- a/Doc/SelectToken.aml +++ b/Doc/SelectToken.aml @@ -28,7 +28,7 @@ SelectToken supports JSONPath queries. Find out more about JSONPath here -http://goessner.net/articles/JsonPath/ +https://goessner.net/articles/JsonPath/ _blank . @@ -50,4 +50,4 @@ Overload:Newtonsoft.Json.Linq.JToken.SelectToken - \ No newline at end of file + diff --git a/Src/Directory.Build.props b/Src/Directory.Build.props new file mode 100644 index 000000000..bafd1cd9e --- /dev/null +++ b/Src/Directory.Build.props @@ -0,0 +1,25 @@ + + + 4.6.2 + 0.10.10 + 4.2.3 + 6.0.0 + 4.3.0 + 1.0.0 + 16.3.0 + 4.8.1 + 3.11.0 + 3.13.0 + 4.4.0 + 1.4.0 + 4.3.0 + 4.3.0 + 4.3.0 + 4.3.0 + 4.3.0 + 4.3.0 + 4.4.0 + 2.3.1 + 2.3.1 + + diff --git a/Src/Newtonsoft.Json.TestConsole/Newtonsoft.Json.TestConsole.csproj b/Src/Newtonsoft.Json.TestConsole/Newtonsoft.Json.TestConsole.csproj index 97a67d43e..b8a43257f 100644 --- a/Src/Newtonsoft.Json.TestConsole/Newtonsoft.Json.TestConsole.csproj +++ b/Src/Newtonsoft.Json.TestConsole/Newtonsoft.Json.TestConsole.csproj @@ -1,7 +1,7 @@  Exe - net46;netcoreapp2.2 + net46;net6.0 latest Newtonsoft.Json.TestConsole Newtonsoft.Json.TestConsole diff --git a/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs b/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs index 3aae21b04..9c5487456 100644 --- a/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs +++ b/Src/Newtonsoft.Json.Tests/Benchmarks/LowLevelBenchmarks.cs @@ -35,7 +35,7 @@ using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Newtonsoft.Json.Utilities; -#if !PORTABLE || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD2_0 || NET6_0_OR_GREATER using MemberTypes = System.Reflection.MemberTypes; using BindingFlags = System.Reflection.BindingFlags; #else diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs index 9c8c7f955..1998ff982 100644 --- a/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs +++ b/Src/Newtonsoft.Json.Tests/Bson/BsonReaderTests.cs @@ -31,7 +31,7 @@ using System.Runtime.Serialization; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Tests.TestObjects; -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -1495,7 +1495,7 @@ public void Utf8Text() Assert.AreEqual(badText, (string)o["test"]); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER public class BigIntegerTestClass { public BigInteger Blah { get; set; } diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterAsyncTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterAsyncTests.cs index ff465efd6..e86bc6f46 100644 --- a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterAsyncTests.cs @@ -26,7 +26,7 @@ #pragma warning disable 618 #if !(NET20 || NET35 || NET40 || PORTABLE40) using System; -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -499,7 +499,7 @@ public async Task DateTimeZoneHandlingAsync() Assert.AreEqual("10-00-00-00-09-30-00-C8-88-07-6B-DC-00-00-00-00", (BitConverter.ToString(ms.ToArray()))); } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task WriteBigIntegerAsync() { diff --git a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs index ae8b61692..850c60a5f 100644 --- a/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Bson/BsonWriterTests.cs @@ -26,7 +26,7 @@ #pragma warning disable 618 using System; using System.Collections.Generic; -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -798,7 +798,7 @@ public void WriteStringReadGuid() Assert.AreEqual(c.AGuid, c2.AGuid.ToString()); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void WriteBigInteger() { diff --git a/Src/Newtonsoft.Json.Tests/Converters/BinaryConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/BinaryConverterTests.cs index 80f96d6fe..fa420c823 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/BinaryConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/BinaryConverterTests.cs @@ -28,7 +28,7 @@ #if !(NET20 || DNXCORE50) using System.Data.Linq; #endif -#if !DNXCORE50 || NETSTANDARD2_0 +#if !DNXCORE50 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Data.SqlTypes; #endif using System.Text; @@ -121,7 +121,7 @@ public void SerializeByteArrayClass() }", json); } -#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class SqlBinaryClass { public SqlBinary SqlBinary { get; set; } diff --git a/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs index 3c1274228..ff3534b16 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/DataSetConverterTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using Newtonsoft.Json.Converters; #if DNXCORE50 diff --git a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs index 610760768..77977febf 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/DataTableConverterTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.IO; using System.Text; using Newtonsoft.Json.Bson; diff --git a/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs index 7cac6eba2..3431bb53a 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/DiscriminatedUnionConverterTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Diagnostics; using System.Reflection; using Microsoft.FSharp.Core; diff --git a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs index 5f0052302..0ee769cf1 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/IsoDateTimeConverterTests.cs @@ -123,7 +123,7 @@ public void SerializeCustomFormattedDateTime() Assert.AreEqual(2006, d.Year); } -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeFormattedDateTimeNewZealandCulture() { diff --git a/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs index 2a6e1dc84..2e1b0af0c 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/StringEnumConverterTests.cs @@ -255,7 +255,7 @@ public void StringEnumConverter_NamingStrategyTypeCtor_Null() ExceptionAssert.Throws( () => new StringEnumConverter(null), @"Value cannot be null. -Parameter name: namingStrategyType"); +Parameter name: namingStrategyType", "Value cannot be null. (Parameter 'namingStrategyType')"); } [Test] @@ -264,7 +264,7 @@ public void StringEnumConverter_NamingStrategyTypeWithArgsCtor_Null() ExceptionAssert.Throws( () => new StringEnumConverter(null, new object[] { true, true, true }, false), @"Value cannot be null. -Parameter name: namingStrategyType"); +Parameter name: namingStrategyType", "Value cannot be null. (Parameter 'namingStrategyType')"); } [Test] diff --git a/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs b/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs index 638c74844..ed8ee1f9b 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/UnixDateTimeConverterTests.cs @@ -25,6 +25,7 @@ using System; using System.Collections.Generic; +using System.Globalization; #if DNXCORE50 using Xunit; using Test = Xunit.FactAttribute; @@ -71,6 +72,17 @@ public void SerializeInvalidDate() ); } + [Test] + public void SerializeDateBeforeEpoch() + { + DateTime date = new DateTime(1964, 2, 7); + long dateSeconds = (long)(date.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalSeconds; + + string result = JsonConvert.SerializeObject(date, new UnixDateTimeConverter { AllowPreEpoch = true }); + + Assert.AreEqual(dateSeconds.ToString(CultureInfo.InvariantCulture), result); + } + [Test] public void WriteJsonInvalidType() { @@ -159,6 +171,19 @@ public void DeserializeInvalidStringToDateTimeOffset() "Cannot convert invalid value to System.DateTimeOffset. Path '', line 1, position 5." ); } + + [Test] + public void DeserializeDateTimeOffsetBeforeEpoch() + { + UnixDateTimeConverter converter = new UnixDateTimeConverter(true); + DateTimeOffset d = new DateTimeOffset(1969, 2, 1, 20, 6, 18, TimeSpan.Zero); + + string json = JsonConvert.SerializeObject(d, converter); + + DateTimeOffset result = JsonConvert.DeserializeObject(json, converter); + + Assert.AreEqual(new DateTimeOffset(1969, 2, 1, 20, 6, 18, TimeSpan.Zero), result); + } #endif [Test] @@ -186,6 +211,14 @@ public void DeserializeInvalidValue() ); } + [Test] + public void DeserializeNegativeIntegerToDateTimeBeforeEpoch() + { + DateTime result = JsonConvert.DeserializeObject("-1514840476", new UnixDateTimeConverter(true)); + + Assert.AreEqual(new DateTime(1921, 12, 31, 02, 58, 44, DateTimeKind.Utc), result); + } + [Test] public void DeserializeInvalidValueType() { @@ -263,6 +296,49 @@ public void ConverterObject() Assert.IsNull(obj2.Object2); Assert.AreEqual(new DateTime(2018, 1, 1, 21, 1, 16, DateTimeKind.Utc), obj2.ObjectNotHandled); } + +#if !NET20 + [Test] + public void ConverterObjectWithDatesBeforeEpoch() + { + PreEpochUnixConverterObject obj1 = new PreEpochUnixConverterObject + { + Date1 = new DateTime(1969, 1, 1, 0, 0, 3, DateTimeKind.Utc), + Date2 = new DateTimeOffset(1969, 1, 1, 0, 0, 3, TimeSpan.Zero) + }; + + string json = JsonConvert.SerializeObject(obj1, Formatting.Indented); + StringAssert.AreEqual(@"{ + ""Date1"": -31535997, + ""Date2"": -31535997 +}", json); + + PreEpochUnixConverterObject obj2 = JsonConvert.DeserializeObject(json); + Assert.IsNotNull(obj2); + + Assert.AreEqual(new DateTime(1969, 1, 1, 0, 0, 3, DateTimeKind.Utc), obj2.Date1); + Assert.AreEqual(new DateTimeOffset(1969, 1, 1, 0, 0, 3, TimeSpan.Zero), obj2.Date2); + } +#else + [Test] + public void ConverterObjectWithDatesBeforeEpoch() + { + PreEpochUnixConverterObject obj1 = new PreEpochUnixConverterObject + { + Date1 = new DateTime(1969, 1, 1, 0, 0, 3, DateTimeKind.Utc) + }; + + string json = JsonConvert.SerializeObject(obj1, Formatting.Indented); + StringAssert.AreEqual(@"{ + ""Date1"": -31535997 +}", json); + + PreEpochUnixConverterObject obj2 = JsonConvert.DeserializeObject(json); + Assert.IsNotNull(obj2); + + Assert.AreEqual(new DateTime(1969, 1, 1, 0, 0, 3, DateTimeKind.Utc), obj2.Date1); + } +#endif } [JsonArray(ItemConverterType = typeof(UnixDateTimeConverter))] @@ -281,4 +357,15 @@ public class UnixConverterObject [JsonConverter(typeof(UnixDateTimeConverter))] public object ObjectNotHandled { get; set; } } + + public class PreEpochUnixConverterObject + { + [JsonConverter(typeof(UnixDateTimeConverter), true)] + public DateTime Date1 { get; set; } + +#if !NET20 + [JsonConverter (typeof(UnixDateTimeConverter), true)] + public DateTimeOffset Date2 { get; set; } +#endif + } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs index f420ef6b4..e621feb37 100644 --- a/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Converters/XmlNodeConverterTest.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Globalization; #if NET20 using Newtonsoft.Json.Utilities.LinqBridge; @@ -58,7 +58,7 @@ namespace Newtonsoft.Json.Tests.Converters [TestFixture] public class XmlNodeConverterTest : TestFixtureBase { -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER private string SerializeXmlNode(XmlNode node) { string json = JsonConvert.SerializeXmlNode(node, Formatting.Indented); @@ -151,7 +151,7 @@ private string IndentXml(string xml) return sw.ToString(); } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeXmlNode_DefaultDate() { @@ -160,6 +160,14 @@ public void DeserializeXmlNode_DefaultDate() Assert.AreEqual("", xmlNode.OuterXml); } + [Test] + public void XmlNode_Null() + { + string json = JsonConvert.SerializeXmlNode(null); + + Assert.AreEqual("null", json); + } + [Test] public void XmlNode_Roundtrip_PropertyNameWithColon() { @@ -305,6 +313,14 @@ public void WriteJsonNull() } #if !NET20 + [Test] + public void XNode_Null() + { + string json = JsonConvert.SerializeXNode(null); + + Assert.AreEqual("null", json); + } + [Test] public void XNode_UnescapeTextContent() { @@ -553,7 +569,7 @@ public void MultipleNamespacesXDocument() } #endif -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void MultipleNamespacesXmlDocument() { @@ -732,7 +748,7 @@ public void GroupElementsOfTheSameName() ", doc.ToString()); } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeEmptyDocument() { @@ -778,7 +794,7 @@ public void SerializeAndDeserializeXmlWithNamespaceInChildrenAndNoValueInChildre Assert.IsTrue(equals); } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeUndeclaredNamespacePrefix() { @@ -793,7 +809,7 @@ public void DeserializeUndeclaredNamespacePrefix() #endif #endif -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeMultipleRootElements() { @@ -1588,7 +1604,7 @@ public void NestedArrays() ] }"; -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot"); string xml = IndentXml(newDoc.InnerXml); @@ -1626,7 +1642,7 @@ public void NestedArrays() ", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting))); #endif -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented); Console.WriteLine(newJson); #endif @@ -1651,7 +1667,7 @@ public void RoundTripNestedArrays() ] }"; -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot", true); StringAssert.AreEqual(@" @@ -1687,7 +1703,7 @@ public void RoundTripNestedArrays() ", IndentXml(newXDoc.ToString(SaveOptions.DisableFormatting))); #endif -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER string newJson = JsonConvert.SerializeXmlNode(newDoc, Formatting.Indented, true); StringAssert.AreEqual(json, newJson); #endif @@ -1713,7 +1729,7 @@ public void MultipleNestedArraysToXml() ] }"; -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER XmlDocument newDoc = JsonConvert.DeserializeXmlNode(json, "myRoot"); Assert.AreEqual(@"113150assets/images/resized/0001/1070/11070v1-max-150x150.jpg189250assets/images/resized/0001/1070/11070v1-max-250x250.jpg341450assets/images/resized/0001/1070/11070v1-max-450x450.jpg", newDoc.InnerXml); @@ -1726,7 +1742,7 @@ public void MultipleNestedArraysToXml() #endif } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void Encoding() { @@ -1741,7 +1757,7 @@ public void Encoding() } #endif -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeComment() { @@ -2792,7 +2808,7 @@ public void DeserializeXNodeDefaultNamespace() } #endif -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeXmlNodeDefaultNamespace() { @@ -3120,7 +3136,7 @@ public void SerializeAndDeserializeXElementWithNamespaceInChildrenRootDontHaveNa } #endif -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeAndDeserializeXmlElementWithNamespaceInChildrenRootDontHaveNameSpace() { @@ -3139,7 +3155,7 @@ public void SerializeAndDeserializeXmlElementWithNamespaceInChildrenRootDontHave Assert.AreEqual(@"AsdAAAadad", xmlBack.OuterXml); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeBigInteger() { diff --git a/Src/Newtonsoft.Json.Tests/DemoTests.cs b/Src/Newtonsoft.Json.Tests/DemoTests.cs index 51b781243..5c24ed448 100644 --- a/Src/Newtonsoft.Json.Tests/DemoTests.cs +++ b/Src/Newtonsoft.Json.Tests/DemoTests.cs @@ -24,11 +24,11 @@ #endregion using System; -#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Buffers; #endif using System.Collections.Generic; -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Data; #endif using System.IO; @@ -596,7 +596,7 @@ public void MergeJson() }", json); } -#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ArrayPooling() { @@ -614,7 +614,7 @@ public void ArrayPooling() } #endif -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeDataTable() { @@ -681,7 +681,7 @@ public void JsonPathRegex() Assert.AreEqual(1, newtonsoftPackages.Count); } -#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task AsyncDemo() { @@ -705,7 +705,7 @@ public async Task AsyncDemo() #endif } -#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class JsonArrayPool : IArrayPool { public static readonly JsonArrayPool Instance = new JsonArrayPool(); diff --git a/Src/Newtonsoft.Json.Tests/Documentation/ConditionalPropertiesTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/ConditionalPropertiesTests.cs index a5eae45ea..ce45016da 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/ConditionalPropertiesTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/ConditionalPropertiesTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs index b3e0486ca..633211862 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/ConvertingJsonAndXmlTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET35 || NET20 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/JsonSchemaTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/JsonSchemaTests.cs index bccc3cfde..29fb5f4ca 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/JsonSchemaTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/JsonSchemaTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER #pragma warning disable 618 using System; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs index 60efb478e..af55e482d 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/LinqToJsonTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/PerformanceTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/PerformanceTests.cs index 93f549bf9..f290a5b4b 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/PerformanceTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/PerformanceTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/ReadingAndWritingJsonTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/ReadingAndWritingJsonTests.cs index f01b19380..f154abf1a 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/ReadingAndWritingJsonTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/ReadingAndWritingJsonTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonReader.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonReader.cs index 3c5dc7168..2cf77075f 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonReader.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonReader.cs @@ -39,7 +39,7 @@ #endif -#if !(DNXCORE50 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(DNXCORE50 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER namespace Newtonsoft.Json.Tests.Documentation.Samples.Json { diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonWriter.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonWriter.cs index 010bd3b7a..51860f956 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonWriter.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Json/CustomJsonWriter.cs @@ -39,7 +39,7 @@ #endif -#if !(DNXCORE50 || NET20) || NETSTANDARD2_0 +#if !(DNXCORE50 || NET20) || NETSTANDARD2_0 || NET6_0_OR_GREATER namespace Newtonsoft.Json.Tests.Documentation.Samples.Json { diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/DeserializeWithLinq.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/DeserializeWithLinq.cs index 4a1bd9d39..0192f6d07 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/DeserializeWithLinq.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/DeserializeWithLinq.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !DNXCORE50 || NETSTANDARD2_0 +#if !DNXCORE50 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/SerializeWithLinq.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/SerializeWithLinq.cs index 89701f8a9..18c59428a 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/SerializeWithLinq.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Linq/SerializeWithLinq.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !DNXCORE50 || NETSTANDARD2_0 +#if !DNXCORE50 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/CustomTraceWriter.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/CustomTraceWriter.cs index c764505bd..b3306dde8 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/CustomTraceWriter.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/CustomTraceWriter.cs @@ -37,7 +37,7 @@ #endif -#if !(DNXCORE50 || NET20 || NET35) || NETSTANDARD2_0 +#if !(DNXCORE50 || NET20 || NET35) || NETSTANDARD2_0 || NET6_0_OR_GREATER namespace Newtonsoft.Json.Tests.Documentation.Samples.Serializer { diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDataSet.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDataSet.cs index 78e65c637..ec7605bea 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDataSet.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDataSet.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDateFormatString.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDateFormatString.cs index dc7a0f0d1..1818ae686 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDateFormatString.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeDateFormatString.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !DNXCORE50 || NETSTANDARD2_0 +#if !DNXCORE50 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeWithDependencyInjection.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeWithDependencyInjection.cs index faceabe97..c15e3eb08 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeWithDependencyInjection.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/DeserializeWithDependencyInjection.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET20 || NET35 || NET40 || DNXCORE50 || PORTABLE40 || PORTABLE) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || DNXCORE50 || PORTABLE40 || PORTABLE) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/NamingStrategyKebabCase.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/NamingStrategyKebabCase.cs new file mode 100644 index 000000000..dfe50dba3 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/NamingStrategyKebabCase.cs @@ -0,0 +1,86 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Documentation.Samples.Serializer +{ + [TestFixture] + public class NamingStrategyKebabCase : TestFixtureBase + { + #region Types + public class User + { + public string UserName { get; set; } + public bool Enabled { get; set; } + } + #endregion + + [Test] + public void Example() + { + #region Usage + User user1 = new User + { + UserName = "jamesn", + Enabled = true + }; + + DefaultContractResolver contractResolver = new DefaultContractResolver + { + NamingStrategy = new KebabCaseNamingStrategy() + }; + + string json = JsonConvert.SerializeObject(user1, new JsonSerializerSettings + { + ContractResolver = contractResolver, + Formatting = Formatting.Indented + }); + + Console.WriteLine(json); + // { + // "user-name": "jamesn", + // "enabled": true + // } + #endregion + + StringAssert.AreEqual(@"{ + ""user-name"": ""jamesn"", + ""enabled"": true +}", json); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/SerializeDataSet.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/SerializeDataSet.cs index 45f7dcb86..a4ccdebc2 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/SerializeDataSet.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Serializer/SerializeDataSet.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJson.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJson.cs index 25c4c4293..856f8cbcb 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJson.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJson.cs @@ -36,7 +36,7 @@ #endif -#if !(DNXCORE50 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(DNXCORE50 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER namespace Newtonsoft.Json.Tests.Documentation.Samples.Xml { diff --git a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJsonForceArray.cs b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJsonForceArray.cs index aeaf7fef3..35b0a3eda 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJsonForceArray.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/Samples/Xml/ConvertXmlToJsonForceArray.cs @@ -36,7 +36,7 @@ #endif -#if !(NET20 || DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER namespace Newtonsoft.Json.Tests.Documentation.Samples.Xml { diff --git a/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs index fbfbd3a8e..5bb3c6d5a 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/SerializationTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/Src/Newtonsoft.Json.Tests/Documentation/TraceWriterTests.cs b/Src/Newtonsoft.Json.Tests/Documentation/TraceWriterTests.cs index b40faea68..c7837e315 100644 --- a/Src/Newtonsoft.Json.Tests/Documentation/TraceWriterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Documentation/TraceWriterTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/Src/Newtonsoft.Json.Tests/ExceptionTests.cs b/Src/Newtonsoft.Json.Tests/ExceptionTests.cs index ce93ecd05..85714d7af 100644 --- a/Src/Newtonsoft.Json.Tests/ExceptionTests.cs +++ b/Src/Newtonsoft.Json.Tests/ExceptionTests.cs @@ -25,7 +25,7 @@ using System; using System.IO; -#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Runtime.Serialization.Formatters.Binary; #endif using Newtonsoft.Json.Schema; @@ -105,7 +105,7 @@ public void JsonSchemaException() } #pragma warning restore 618 -#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void BinarySerializeException() { @@ -113,7 +113,9 @@ public void BinarySerializeException() using (var memoryStream = new MemoryStream()) { var binaryFormatter = new BinaryFormatter(); +#pragma warning disable SYSLIB0011 // Type or member is obsolete binaryFormatter.Serialize(memoryStream, exception); +#pragma warning restore SYSLIB0011 // Type or member is obsolete } } #endif diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1327.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1327.cs index 0d2f665a6..674364110 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1327.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1327.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.Linq; @@ -47,7 +47,7 @@ namespace Newtonsoft.Json.Tests.Issues [TestFixture] public class Issue1327 : TestFixtureBase { -#if !PORTABLE || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD2_0 || NET6_0_OR_GREATER public class PersonWithXmlNode { public XmlNode TestXml { get; set; } @@ -71,7 +71,7 @@ public class PersonWithXObject } #endif -#if !PORTABLE || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void Test_XmlNode() { diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1404.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1404.cs index 51025c164..a0ec4ad9a 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1404.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1404.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Data; using System.IO; diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1445.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1445.cs index a641f44ea..72d4fa189 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1445.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1445.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(PORTABLE) || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Data; using System.Linq; diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1569.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1569.cs index d2552b831..f346fade7 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1569.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1569.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.IO; using System.Text; diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1597.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1597.cs index 4d2bdda53..91a8d4373 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1597.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1597.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET20 || NET35 || NET40 || PORTABLE40 || PORTABLE) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || PORTABLE40 || PORTABLE) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1620.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1620.cs index 0101e813e..6f673f963 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1620.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1620.cs @@ -36,7 +36,7 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; -#if PORTABLE && !NETSTANDARD2_0 +#if PORTABLE && !(NETSTANDARD2_0 || NET6_0_OR_GREATER) using BindingFlags = Newtonsoft.Json.Utilities.BindingFlags; #else using BindingFlags = System.Reflection.BindingFlags; diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1734.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1734.cs index a84475196..ec8724dc1 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1734.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1734.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq.JsonPath; using System; diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1757.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1757.cs index 83704f5ab..d1af5c88e 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1757.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1757.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if (NETSTANDARD2_0) +#if (NETSTANDARD2_0 || NET6_0_OR_GREATER) using System; using System.Collections; using System.Collections.Generic; diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1798.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1798.cs index b311871cf..1a8c7dc0e 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1798.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1798.cs @@ -90,7 +90,7 @@ public void Test_DefaultContractResolver() var objectContract = (JsonObjectContract) resolver.ResolveContract(typeof(NonSerializableException)); Assert.IsFalse(objectContract.Properties.Contains("TargetSite")); -#if (PORTABLE40 || PORTABLE || NETSTANDARD1_3) && !NETSTANDARD2_0 +#if (PORTABLE40 || PORTABLE) && !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) objectContract = (JsonObjectContract) resolver.ResolveContract(typeof(Exception)); Assert.IsFalse(objectContract.Properties.Contains("TargetSite")); #else diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1962.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1962.cs new file mode 100644 index 000000000..b9c144e0e --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1962.cs @@ -0,0 +1,86 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System.Linq; +using Newtonsoft.Json.Linq; +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue1962 + { + [Test] + public void Test_Default() + { + string json = @"// comment +[ 1, 2, 42 ]"; + JToken token = JToken.Parse(json); + + Assert.AreEqual(JTokenType.Comment, token.Type); + Assert.AreEqual(" comment", ((JValue)token).Value); + } + + [Test] + public void Test_LoadComments() + { + string json = @"// comment +[ 1, 2, 42 ]"; + JToken token = JToken.Parse(json, new JsonLoadSettings + { + CommentHandling = CommentHandling.Load + }); + + Assert.AreEqual(JTokenType.Comment, token.Type); + Assert.AreEqual(" comment", ((JValue)token).Value); + + int[] obj = token.ToObject(); + Assert.IsNull(obj); + } + + [Test] + public void Test_IgnoreComments() + { + string json = @"// comment +[ 1, 2, 42 ]"; + JToken token = JToken.Parse(json, new JsonLoadSettings + { + CommentHandling = CommentHandling.Ignore + }); + + Assert.AreEqual(JTokenType.Array, token.Type); + Assert.AreEqual(3, token.Count()); + Assert.AreEqual(1, (int)token[0]); + Assert.AreEqual(2, (int)token[1]); + Assert.AreEqual(42, (int)token[2]); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue1984.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue1984.cs index e552cbf28..0dde517c5 100644 --- a/Src/Newtonsoft.Json.Tests/Issues/Issue1984.cs +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue1984.cs @@ -37,6 +37,7 @@ namespace Newtonsoft.Json.Tests.Issues { + [TestFixture] public class Issue1984 { [Test] diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2082.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2082.cs new file mode 100644 index 000000000..f69ae3c1e --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2082.cs @@ -0,0 +1,76 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !NET20 +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2082 + { + [Test] + public void Test() + { + CamelCaseNamingStrategy namingStrategy = new CamelCaseNamingStrategy(processDictionaryKeys: true, overrideSpecifiedNames: false); + + TestClass c = new TestClass { Value = TestEnum.UpperCaseName }; + string json = JsonConvert.SerializeObject(c, new JsonSerializerSettings + { + ContractResolver = new DefaultContractResolver + { + NamingStrategy = namingStrategy + }, + Converters = new[] { new StringEnumConverter { NamingStrategy = namingStrategy } } + }); + + Assert.AreEqual(@"{""value"":""UPPER_CASE_NAME""}", json); + } + + public class TestClass + { + public TestEnum Value { get; set; } + } + + public enum TestEnum + { + [EnumMember(Value = "UPPER_CASE_NAME")] + UpperCaseName + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2156.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2156.cs new file mode 100644 index 000000000..b04354319 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2156.cs @@ -0,0 +1,65 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using Newtonsoft.Json.Linq; +using System.Linq; +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2156 + { + [Test] + public void Test() + { + string json = @" + { + ""root"": { + ""a"": { + ""name"": ""John"", + ""b"": { + ""name"": ""Sarah"" + } + } + } + }"; + + JToken t = JToken.Parse(json); + + int count1 = t.SelectTokens("$..a.name").Count(); // result: 1, expected: 1 + int count2 = t.SelectTokens("$..['a']['name']").Count(); // result: 2, expected: 1 + + Assert.AreEqual(1, count1); + Assert.AreEqual(1, count2); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs new file mode 100644 index 000000000..64071d4e4 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2165.cs @@ -0,0 +1,83 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.IO; +#if !(NET20 || NET35 || NET40 || PORTABLE40) +using System.Threading.Tasks; +#endif +using Newtonsoft.Json.Linq; +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2165 + { + [Test] + public void Test_Deserializer() + { + ExceptionAssert.Throws( + () => JsonConvert.DeserializeObject("{"), + "Unexpected end when reading token. Path ''."); + } + + [Test] + public void Test() + { + StringWriter w = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(w); + + var jsonReader = new JsonTextReader(new StringReader("{")); + jsonReader.Read(); + + ExceptionAssert.Throws( + () => writer.WriteToken(jsonReader), + "Unexpected end when reading token. Path ''."); + } + +#if !(NET20 || NET35 || NET40 || PORTABLE40) + [Test] + public async Task TestAsync() + { + StringWriter w = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(w); + + var jsonReader = new JsonTextReader(new StringReader("{")); + await jsonReader.ReadAsync(); + + await ExceptionAssert.ThrowsAsync( + () => writer.WriteTokenAsync(jsonReader), + "Unexpected end when reading token. Path ''."); + } +#endif + } +} diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2176.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2176.cs new file mode 100644 index 000000000..a0f42bd30 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2176.cs @@ -0,0 +1,576 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !(NETSTANDARD1_0 || NETSTANDARD1_3) +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2176 + { + [Test] + public void Test() + { + Dummy o = JsonConvert.DeserializeObject(Json); + Assert.AreEqual(0, o.P0); + Assert.AreEqual(256, o.P256); + } + + public class Dummy + { + public int P0 { get; } + public int P1 { get; } + public int P2 { get; } + public int P3 { get; } + public int P4 { get; } + public int P5 { get; } + public int P6 { get; } + public int P7 { get; } + public int P8 { get; } + public int P9 { get; } + public int P10 { get; } + public int P11 { get; } + public int P12 { get; } + public int P13 { get; } + public int P14 { get; } + public int P15 { get; } + public int P16 { get; } + public int P17 { get; } + public int P18 { get; } + public int P19 { get; } + public int P20 { get; } + public int P21 { get; } + public int P22 { get; } + public int P23 { get; } + public int P24 { get; } + public int P25 { get; } + public int P26 { get; } + public int P27 { get; } + public int P28 { get; } + public int P29 { get; } + public int P30 { get; } + public int P31 { get; } + public int P32 { get; } + public int P33 { get; } + public int P34 { get; } + public int P35 { get; } + public int P36 { get; } + public int P37 { get; } + public int P38 { get; } + public int P39 { get; } + public int P40 { get; } + public int P41 { get; } + public int P42 { get; } + public int P43 { get; } + public int P44 { get; } + public int P45 { get; } + public int P46 { get; } + public int P47 { get; } + public int P48 { get; } + public int P49 { get; } + public int P50 { get; } + public int P51 { get; } + public int P52 { get; } + public int P53 { get; } + public int P54 { get; } + public int P55 { get; } + public int P56 { get; } + public int P57 { get; } + public int P58 { get; } + public int P59 { get; } + public int P60 { get; } + public int P61 { get; } + public int P62 { get; } + public int P63 { get; } + public int P64 { get; } + public int P65 { get; } + public int P66 { get; } + public int P67 { get; } + public int P68 { get; } + public int P69 { get; } + public int P70 { get; } + public int P71 { get; } + public int P72 { get; } + public int P73 { get; } + public int P74 { get; } + public int P75 { get; } + public int P76 { get; } + public int P77 { get; } + public int P78 { get; } + public int P79 { get; } + public int P80 { get; } + public int P81 { get; } + public int P82 { get; } + public int P83 { get; } + public int P84 { get; } + public int P85 { get; } + public int P86 { get; } + public int P87 { get; } + public int P88 { get; } + public int P89 { get; } + public int P90 { get; } + public int P91 { get; } + public int P92 { get; } + public int P93 { get; } + public int P94 { get; } + public int P95 { get; } + public int P96 { get; } + public int P97 { get; } + public int P98 { get; } + public int P99 { get; } + public int P100 { get; } + public int P101 { get; } + public int P102 { get; } + public int P103 { get; } + public int P104 { get; } + public int P105 { get; } + public int P106 { get; } + public int P107 { get; } + public int P108 { get; } + public int P109 { get; } + public int P110 { get; } + public int P111 { get; } + public int P112 { get; } + public int P113 { get; } + public int P114 { get; } + public int P115 { get; } + public int P116 { get; } + public int P117 { get; } + public int P118 { get; } + public int P119 { get; } + public int P120 { get; } + public int P121 { get; } + public int P122 { get; } + public int P123 { get; } + public int P124 { get; } + public int P125 { get; } + public int P126 { get; } + public int P127 { get; } + public int P128 { get; } + public int P129 { get; } + public int P130 { get; } + public int P131 { get; } + public int P132 { get; } + public int P133 { get; } + public int P134 { get; } + public int P135 { get; } + public int P136 { get; } + public int P137 { get; } + public int P138 { get; } + public int P139 { get; } + public int P140 { get; } + public int P141 { get; } + public int P142 { get; } + public int P143 { get; } + public int P144 { get; } + public int P145 { get; } + public int P146 { get; } + public int P147 { get; } + public int P148 { get; } + public int P149 { get; } + public int P150 { get; } + public int P151 { get; } + public int P152 { get; } + public int P153 { get; } + public int P154 { get; } + public int P155 { get; } + public int P156 { get; } + public int P157 { get; } + public int P158 { get; } + public int P159 { get; } + public int P160 { get; } + public int P161 { get; } + public int P162 { get; } + public int P163 { get; } + public int P164 { get; } + public int P165 { get; } + public int P166 { get; } + public int P167 { get; } + public int P168 { get; } + public int P169 { get; } + public int P170 { get; } + public int P171 { get; } + public int P172 { get; } + public int P173 { get; } + public int P174 { get; } + public int P175 { get; } + public int P176 { get; } + public int P177 { get; } + public int P178 { get; } + public int P179 { get; } + public int P180 { get; } + public int P181 { get; } + public int P182 { get; } + public int P183 { get; } + public int P184 { get; } + public int P185 { get; } + public int P186 { get; } + public int P187 { get; } + public int P188 { get; } + public int P189 { get; } + public int P190 { get; } + public int P191 { get; } + public int P192 { get; } + public int P193 { get; } + public int P194 { get; } + public int P195 { get; } + public int P196 { get; } + public int P197 { get; } + public int P198 { get; } + public int P199 { get; } + public int P200 { get; } + public int P201 { get; } + public int P202 { get; } + public int P203 { get; } + public int P204 { get; } + public int P205 { get; } + public int P206 { get; } + public int P207 { get; } + public int P208 { get; } + public int P209 { get; } + public int P210 { get; } + public int P211 { get; } + public int P212 { get; } + public int P213 { get; } + public int P214 { get; } + public int P215 { get; } + public int P216 { get; } + public int P217 { get; } + public int P218 { get; } + public int P219 { get; } + public int P220 { get; } + public int P221 { get; } + public int P222 { get; } + public int P223 { get; } + public int P224 { get; } + public int P225 { get; } + public int P226 { get; } + public int P227 { get; } + public int P228 { get; } + public int P229 { get; } + public int P230 { get; } + public int P231 { get; } + public int P232 { get; } + public int P233 { get; } + public int P234 { get; } + public int P235 { get; } + public int P236 { get; } + public int P237 { get; } + public int P238 { get; } + public int P239 { get; } + public int P240 { get; } + public int P241 { get; } + public int P242 { get; } + public int P243 { get; } + public int P244 { get; } + public int P245 { get; } + public int P246 { get; } + public int P247 { get; } + public int P248 { get; } + public int P249 { get; } + public int P250 { get; } + public int P251 { get; } + public int P252 { get; } + public int P253 { get; } + public int P254 { get; } + public int P255 { get; } + public int P256 { get; } + + public Dummy(int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12, int p13, int p14, int p15, int p16, int p17, int p18, int p19, int p20, int p21, int p22, int p23, int p24, int p25, int p26, int p27, int p28, int p29, int p30, int p31, int p32, int p33, int p34, int p35, int p36, int p37, int p38, int p39, int p40, int p41, int p42, int p43, int p44, int p45, int p46, int p47, int p48, int p49, int p50, int p51, int p52, int p53, int p54, int p55, int p56, int p57, int p58, int p59, int p60, int p61, int p62, int p63, int p64, int p65, int p66, int p67, int p68, int p69, int p70, int p71, int p72, int p73, int p74, int p75, int p76, int p77, int p78, int p79, int p80, int p81, int p82, int p83, int p84, int p85, int p86, int p87, int p88, int p89, int p90, int p91, int p92, int p93, int p94, int p95, int p96, int p97, int p98, int p99, int p100, int p101, int p102, int p103, int p104, int p105, int p106, int p107, int p108, int p109, int p110, int p111, int p112, int p113, int p114, int p115, int p116, int p117, int p118, int p119, int p120, int p121, int p122, int p123, int p124, int p125, int p126, int p127, int p128, int p129, int p130, int p131, int p132, int p133, int p134, int p135, int p136, int p137, int p138, int p139, int p140, int p141, int p142, int p143, int p144, int p145, int p146, int p147, int p148, int p149, int p150, int p151, int p152, int p153, int p154, int p155, int p156, int p157, int p158, int p159, int p160, int p161, int p162, int p163, int p164, int p165, int p166, int p167, int p168, int p169, int p170, int p171, int p172, int p173, int p174, int p175, int p176, int p177, int p178, int p179, int p180, int p181, int p182, int p183, int p184, int p185, int p186, int p187, int p188, int p189, int p190, int p191, int p192, int p193, int p194, int p195, int p196, int p197, int p198, int p199, int p200, int p201, int p202, int p203, int p204, int p205, int p206, int p207, int p208, int p209, int p210, int p211, int p212, int p213, int p214, int p215, int p216, int p217, int p218, int p219, int p220, int p221, int p222, int p223, int p224, int p225, int p226, int p227, int p228, int p229, int p230, int p231, int p232, int p233, int p234, int p235, int p236, int p237, int p238, int p239, int p240, int p241, int p242, int p243, int p244, int p245, int p246, int p247, int p248, int p249, int p250, int p251, int p252, int p253, int p254, int p255, int p256) + { + P0 = p0; + P256 = p256; + } + } + + public const string Json = @"{ + ""p0"" : 0, + ""p1"" : 1, + ""p2"" : 2, + ""p3"" : 3, + ""p4"" : 4, + ""p5"" : 5, + ""p6"" : 6, + ""p7"" : 7, + ""p8"" : 8, + ""p9"" : 9, + ""p10"" : 10, + ""p11"" : 11, + ""p12"" : 12, + ""p13"" : 13, + ""p14"" : 14, + ""p15"" : 15, + ""p16"" : 16, + ""p17"" : 17, + ""p18"" : 18, + ""p19"" : 19, + ""p20"" : 20, + ""p21"" : 21, + ""p22"" : 22, + ""p23"" : 23, + ""p24"" : 24, + ""p25"" : 25, + ""p26"" : 26, + ""p27"" : 27, + ""p28"" : 28, + ""p29"" : 29, + ""p30"" : 30, + ""p31"" : 31, + ""p32"" : 32, + ""p33"" : 33, + ""p34"" : 34, + ""p35"" : 35, + ""p36"" : 36, + ""p37"" : 37, + ""p38"" : 38, + ""p39"" : 39, + ""p40"" : 40, + ""p41"" : 41, + ""p42"" : 42, + ""p43"" : 43, + ""p44"" : 44, + ""p45"" : 45, + ""p46"" : 46, + ""p47"" : 47, + ""p48"" : 48, + ""p49"" : 49, + ""p50"" : 50, + ""p51"" : 51, + ""p52"" : 52, + ""p53"" : 53, + ""p54"" : 54, + ""p55"" : 55, + ""p56"" : 56, + ""p57"" : 57, + ""p58"" : 58, + ""p59"" : 59, + ""p60"" : 60, + ""p61"" : 61, + ""p62"" : 62, + ""p63"" : 63, + ""p64"" : 64, + ""p65"" : 65, + ""p66"" : 66, + ""p67"" : 67, + ""p68"" : 68, + ""p69"" : 69, + ""p70"" : 70, + ""p71"" : 71, + ""p72"" : 72, + ""p73"" : 73, + ""p74"" : 74, + ""p75"" : 75, + ""p76"" : 76, + ""p77"" : 77, + ""p78"" : 78, + ""p79"" : 79, + ""p80"" : 80, + ""p81"" : 81, + ""p82"" : 82, + ""p83"" : 83, + ""p84"" : 84, + ""p85"" : 85, + ""p86"" : 86, + ""p87"" : 87, + ""p88"" : 88, + ""p89"" : 89, + ""p90"" : 90, + ""p91"" : 91, + ""p92"" : 92, + ""p93"" : 93, + ""p94"" : 94, + ""p95"" : 95, + ""p96"" : 96, + ""p97"" : 97, + ""p98"" : 98, + ""p99"" : 99, + ""p100"" : 100, + ""p101"" : 101, + ""p102"" : 102, + ""p103"" : 103, + ""p104"" : 104, + ""p105"" : 105, + ""p106"" : 106, + ""p107"" : 107, + ""p108"" : 108, + ""p109"" : 109, + ""p110"" : 110, + ""p111"" : 111, + ""p112"" : 112, + ""p113"" : 113, + ""p114"" : 114, + ""p115"" : 115, + ""p116"" : 116, + ""p117"" : 117, + ""p118"" : 118, + ""p119"" : 119, + ""p120"" : 120, + ""p121"" : 121, + ""p122"" : 122, + ""p123"" : 123, + ""p124"" : 124, + ""p125"" : 125, + ""p126"" : 126, + ""p127"" : 127, + ""p128"" : 128, + ""p129"" : 129, + ""p130"" : 130, + ""p131"" : 131, + ""p132"" : 132, + ""p133"" : 133, + ""p134"" : 134, + ""p135"" : 135, + ""p136"" : 136, + ""p137"" : 137, + ""p138"" : 138, + ""p139"" : 139, + ""p140"" : 140, + ""p141"" : 141, + ""p142"" : 142, + ""p143"" : 143, + ""p144"" : 144, + ""p145"" : 145, + ""p146"" : 146, + ""p147"" : 147, + ""p148"" : 148, + ""p149"" : 149, + ""p150"" : 150, + ""p151"" : 151, + ""p152"" : 152, + ""p153"" : 153, + ""p154"" : 154, + ""p155"" : 155, + ""p156"" : 156, + ""p157"" : 157, + ""p158"" : 158, + ""p159"" : 159, + ""p160"" : 160, + ""p161"" : 161, + ""p162"" : 162, + ""p163"" : 163, + ""p164"" : 164, + ""p165"" : 165, + ""p166"" : 166, + ""p167"" : 167, + ""p168"" : 168, + ""p169"" : 169, + ""p170"" : 170, + ""p171"" : 171, + ""p172"" : 172, + ""p173"" : 173, + ""p174"" : 174, + ""p175"" : 175, + ""p176"" : 176, + ""p177"" : 177, + ""p178"" : 178, + ""p179"" : 179, + ""p180"" : 180, + ""p181"" : 181, + ""p182"" : 182, + ""p183"" : 183, + ""p184"" : 184, + ""p185"" : 185, + ""p186"" : 186, + ""p187"" : 187, + ""p188"" : 188, + ""p189"" : 189, + ""p190"" : 190, + ""p191"" : 191, + ""p192"" : 192, + ""p193"" : 193, + ""p194"" : 194, + ""p195"" : 195, + ""p196"" : 196, + ""p197"" : 197, + ""p198"" : 198, + ""p199"" : 199, + ""p200"" : 200, + ""p201"" : 201, + ""p202"" : 202, + ""p203"" : 203, + ""p204"" : 204, + ""p205"" : 205, + ""p206"" : 206, + ""p207"" : 207, + ""p208"" : 208, + ""p209"" : 209, + ""p210"" : 210, + ""p211"" : 211, + ""p212"" : 212, + ""p213"" : 213, + ""p214"" : 214, + ""p215"" : 215, + ""p216"" : 216, + ""p217"" : 217, + ""p218"" : 218, + ""p219"" : 219, + ""p220"" : 220, + ""p221"" : 221, + ""p222"" : 222, + ""p223"" : 223, + ""p224"" : 224, + ""p225"" : 225, + ""p226"" : 226, + ""p227"" : 227, + ""p228"" : 228, + ""p229"" : 229, + ""p230"" : 230, + ""p231"" : 231, + ""p232"" : 232, + ""p233"" : 233, + ""p234"" : 234, + ""p235"" : 235, + ""p236"" : 236, + ""p237"" : 237, + ""p238"" : 238, + ""p239"" : 239, + ""p240"" : 240, + ""p241"" : 241, + ""p242"" : 242, + ""p243"" : 243, + ""p244"" : 244, + ""p245"" : 245, + ""p246"" : 246, + ""p247"" : 247, + ""p248"" : 248, + ""p249"" : 249, + ""p250"" : 250, + ""p251"" : 251, + ""p252"" : 252, + ""p253"" : 253, + ""p254"" : 254, + ""p255"" : 255, + ""p256"" : 256, +}"; + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2444.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2444.cs new file mode 100644 index 000000000..4932d15f7 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2444.cs @@ -0,0 +1,88 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !(NETSTANDARD1_0 || NETSTANDARD1_3) +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2444 + { + [Test] + public void Test() + { + var namingStrategy = new SnakeCaseNamingStrategy(); + var settings = new JsonSerializerSettings + { + ContractResolver = new DefaultContractResolver + { + NamingStrategy = namingStrategy + } + }; + + string json = @"{""dict"":{""value1"":""a"",""text_value"":""b""}}"; + DataClass c = JsonConvert.DeserializeObject(json, settings); + + Assert.AreEqual(2, c.Dict.Count); + Assert.AreEqual("a", c.Dict[MyEnum.Value1]); + Assert.AreEqual("b", c.Dict[MyEnum.TextValue]); + + string json1 = @"{""dict"":{""Value1"":""a"",""TextValue"":""b""}}"; + DataClass c1 = JsonConvert.DeserializeObject(json1, settings); + + Assert.AreEqual(2, c1.Dict.Count); + Assert.AreEqual("a", c1.Dict[MyEnum.Value1]); + Assert.AreEqual("b", c1.Dict[MyEnum.TextValue]); + + // Non-dictionary values should still error + ExceptionAssert.Throws(() => + { + JsonConvert.DeserializeObject>(@"[""text_value""]", settings); + }, @"Error converting value ""text_value"" to type 'Newtonsoft.Json.Tests.Issues.Issue2444+MyEnum'. Path '[0]', line 1, position 13."); + } + + public enum MyEnum + { + Value1, + TextValue + } + + public class DataClass + { + public Dictionary Dict { get; set; } + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2450.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2450.cs new file mode 100644 index 000000000..ee744c908 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2450.cs @@ -0,0 +1,97 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if (NET45 || NET50) +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; +using System.Collections; +using System; + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2450 + { + [Test] + public void Test() + { + var resolver = new DefaultContractResolver(); + JsonContract contract; + + contract = resolver.ResolveContract(typeof(Dict)); + Assert.IsTrue(contract is JsonDictionaryContract); + + contract = resolver.ResolveContract(typeof(Dict?)); + Assert.IsTrue(contract is JsonDictionaryContract); + } + + [Test] + public void Test_Serialize() + { + Dict d = new Dict(new Dictionary + { + ["prop1"] = 1, + ["prop2"] = 2 + }); + + string json = JsonConvert.SerializeObject(d); + Assert.AreEqual(@"{""prop1"":1,""prop2"":2}", json); + } + + [Test] + public void Test_Deserialize() + { + string json = @"{""prop1"":1,""prop2"":2}"; + + var d = JsonConvert.DeserializeObject(json); + Assert.AreEqual(1, d.Value["prop1"]); + Assert.AreEqual(2, d.Value["prop2"]); + } + + public struct Dict : IReadOnlyDictionary + { + private readonly IDictionary _dict; + public Dict(IDictionary dict) => _dict = dict; + + public object this[string key] => _dict[key]; + public IEnumerable Keys => _dict.Keys; + public IEnumerable Values => _dict.Values; + public int Count => _dict.Count; + public bool ContainsKey(string key) => _dict.ContainsKey(key); + public IEnumerator> GetEnumerator() => _dict.GetEnumerator(); + public bool TryGetValue(string key, out object value) => _dict.TryGetValue(key, out value); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2484.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2484.cs new file mode 100644 index 000000000..d779bb184 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2484.cs @@ -0,0 +1,55 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if (NET45 || NET5_0_OR_GREATER) +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; +using System.Collections; +using System; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2484 + { + [Test] + public void Test() + { + var json = "[]"; + var ex = ExceptionAssert.Throws(() => JsonConvert.DeserializeObject(json, typeof(JObject))); + Assert.AreEqual("Deserialized JSON type 'Newtonsoft.Json.Linq.JArray' is not compatible with expected type 'Newtonsoft.Json.Linq.JObject'. Path '', line 1, position 2.", ex.Message); + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2492.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2492.cs new file mode 100644 index 000000000..34146a665 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2492.cs @@ -0,0 +1,77 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if (NET45 || NET5_0_OR_GREATER) +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; +using System.Collections; +using System; +using System.IO; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2492 + { + [Test] + public void Test_Object() + { + string jsontext = @"{ ""ABC"": //DEF +{}}"; + + using var stringReader = new StringReader(jsontext); + using var jsonReader = new JsonTextReader(stringReader); + + JsonSerializer serializer = JsonSerializer.Create(); + var x = serializer.Deserialize(jsonReader); + + Assert.AreEqual(JTokenType.Object, x["ABC"].Type); + } + + [Test] + public void Test_Integer() + { + string jsontext = "{ \"ABC\": /*DEF*/ 1}"; + + using var stringReader = new StringReader(jsontext); + using var jsonReader = new JsonTextReader(stringReader); + + JsonSerializer serializer = JsonSerializer.Create(); + var x = serializer.Deserialize(jsonReader); + + Assert.AreEqual(JTokenType.Integer, x["ABC"].Type); + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2504.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2504.cs new file mode 100644 index 000000000..9ff3be6e7 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2504.cs @@ -0,0 +1,121 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if (NET45 || NET5_0_OR_GREATER) +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; +using System.Collections; +using System; +using System.IO; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2504 : TestFixtureBase + { + [Test] + public void Test() + { + string jsontext = GetNestedJson(150); + + var o = JsonConvert.DeserializeObject(jsontext, new JsonSerializerSettings + { + Converters = new List { new TestConverter() }, + MaxDepth = 150 + }); + + Assert.AreEqual(150, GetDepth(o.Children)); + } + + [Test] + public void Test_Failure() + { + string jsontext = GetNestedJson(150); + + string expectedMessage = @"The reader's MaxDepth of 100 has been exceeded. Path '0.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99', line 101, position 207."; + + ExceptionAssert.Throws(() => JsonConvert.DeserializeObject(jsontext, new JsonSerializerSettings + { + Converters = new List { new TestConverter() }, + MaxDepth = 100 + }), expectedMessage); + } + + private static int GetDepth(JToken o) + { + int depth = 1; + while (o.First != null) + { + o = o.First; + if (o.Type == JTokenType.Object) + { + depth++; + } + } + + return depth; + } + + private class TestObject + { + public JToken Children { get; set; } + } + + private class TestConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(TestObject); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + JToken token = JToken.Load(reader); + + var newToken = token.ToObject(serializer); + + return new TestObject + { + Children = newToken + }; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2529.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2529.cs new file mode 100644 index 000000000..8406bfc0c --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2529.cs @@ -0,0 +1,61 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if (NET45 || NET5_0_OR_GREATER) +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Converters; +using System.Collections; +using System; +using System.IO; +using Newtonsoft.Json.Linq; + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2529 : TestFixtureBase + { + [Test] + public void Test() + { + Something something = JsonConvert.DeserializeObject("{ \"foo\": [] }"); + + Assert.AreEqual(JTokenType.Array, something.Foo.Type); + } + + private class Something + { + public JToken Foo { get; set; } = JValue.CreateNull(); + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2638.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2638.cs new file mode 100644 index 000000000..c32fe4c6c --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2638.cs @@ -0,0 +1,129 @@ +#region License +// Copyright (c) 2022 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using Newtonsoft.Json.Linq; +using System.Globalization; +using Newtonsoft.Json.Tests.Documentation.Samples.Linq; + +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2638 + { + [Test] + public void DeserilizeUsesSharedBooleans() + { + Test(true); + Test(false); + + static void Test(bool value) + { + var obj = (JObject)JToken.Parse(@"{""x"": XXX, ""y"": XXX}".Replace("XXX", value ? "true" : "false")); + var x = ((JValue)obj["x"]).Value; + var y = ((JValue)obj["y"]).Value; + + Assert.AreEqual(value, (bool)x); + Assert.AreEqual(value, (bool)y); + Assert.AreSame(x, y); + } + } + + [Test] + public void DeserilizeUsesSharedDoubleZeros() + { + Test(0, true); + Test(double.NaN, true); + Test(double.NegativeInfinity, true); + Test(double.PositiveInfinity, true); + Test(1, false); + Test(42.42, false); + + static void Test(double value, bool expectSame) + { + var obj = (JObject)JToken.Parse(@"{""x"": XXX, ""y"": XXX}".Replace("XXX", value.ToString("0.0###", CultureInfo.InvariantCulture))); + var x = ((JValue)obj["x"]).Value; + var y = ((JValue)obj["y"]).Value; + + Assert.AreEqual(value, (double)x); + Assert.AreEqual(value, (double)y); + if (expectSame) + { + Assert.AreSame(x, y); + } + else + { + Assert.AreNotSame(x, y); + } + var unboxed = (double)x; + Assert.AreEqual(double.IsNaN(value), double.IsNaN(unboxed)); + Assert.AreEqual(double.IsPositiveInfinity(value), double.IsPositiveInfinity(unboxed)); + Assert.AreEqual(double.IsNegativeInfinity(value), double.IsNegativeInfinity(unboxed)); + } + } + + [Test] + public void DeserilizeUsesSharedSmallInt64() + { + Test(-2, false); + Test(-1, true); + Test(0, true); + Test(1, true); + Test(2, true); + Test(3, true); + Test(4, true); + Test(5, true); + Test(6, true); + Test(7, true); + Test(8, true); + Test(9, false); + + static void Test(long value, bool expectSame) + { + var obj = (JObject)JToken.Parse(@"{""x"": XXX, ""y"": XXX}".Replace("XXX", value.ToString(CultureInfo.InvariantCulture))); + var x = ((JValue)obj["x"]).Value; + var y = ((JValue)obj["y"]).Value; + + Assert.AreEqual(value, (long)x); + Assert.AreEqual(value, (long)y); + if (expectSame) + { + Assert.AreSame(x, y); + } + else + { + Assert.AreNotSame(x, y); + } + } + } + } +} diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2694.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2694.cs new file mode 100644 index 000000000..fbb1a947e --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2694.cs @@ -0,0 +1,158 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +#if DNXCORE50 +using System.Reflection; +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2694 : TestFixtureBase + { +#if NET6_0_OR_GREATER + [Test] + public async Task Test_Reader_DisposeAsync() + { + JsonTextReader reader = new JsonTextReader(new StringReader("{}")); + IAsyncDisposable asyncDisposable = reader; + await asyncDisposable.DisposeAsync(); + + await ExceptionAssert.ThrowsAsync(() => reader.ReadAsync(), + "Unexpected state: Closed. Path '', line 1, position 0."); + } + + [Test] + public async Task Test_Writer_DisposeAsync() + { + MemoryStream ms = new MemoryStream(); + Stream s = new AsyncOnlyStream(ms); + StreamWriter sr = new StreamWriter(s, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), 2, leaveOpen: true); + await using (JsonTextWriter writer = new JsonTextWriter(sr)) + { + await writer.WriteStartObjectAsync(); + } + + string json = Encoding.UTF8.GetString(ms.ToArray()); + Assert.AreEqual("{}", json); + } +#endif + + [Test] + public async Task Test_Writer_CloseAsync() + { + MemoryStream ms = new MemoryStream(); + Stream s = new AsyncOnlyStream(ms); + StreamWriter sr = new StreamWriter(s, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), 2, leaveOpen: true); + JsonTextWriter writer = new JsonTextWriter(sr); + await writer.WriteStartObjectAsync(); + + await writer.CloseAsync(); + + string json = Encoding.UTF8.GetString(ms.ToArray()); + Assert.AreEqual("{}", json); + } + + public class AsyncOnlyStream : Stream + { + private readonly Stream _innerStream; + private int _unflushedContentLength; + + public AsyncOnlyStream(Stream innerStream) + { + _innerStream = innerStream; + } + + public override void Flush() + { + // It's ok to call Flush if the content was already processed with FlushAsync. + if (_unflushedContentLength > 0) + { + throw new Exception($"Flush when there is {_unflushedContentLength} bytes buffered."); + } + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + _unflushedContentLength = 0; + return _innerStream.FlushAsync(cancellationToken); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _innerStream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _innerStream.SetLength(value); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return _innerStream.ReadAsync(buffer, offset, count, cancellationToken); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + _unflushedContentLength += count; + return _innerStream.WriteAsync(buffer, offset, count, cancellationToken); + } + + public override bool CanRead => _innerStream.CanRead; + public override bool CanSeek => _innerStream.CanSeek; + public override bool CanWrite => _innerStream.CanWrite; + public override long Length => _innerStream.Length; + + public override long Position + { + get => _innerStream.Position; + set => _innerStream.Position = value; + } + } + } +} +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2708.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2708.cs new file mode 100644 index 000000000..149544e18 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2708.cs @@ -0,0 +1,81 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !NET20 +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Text; +using System.Threading; +using Newtonsoft.Json.Linq; +#if DNXCORE50 +using System.Reflection; +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2708 : TestFixtureBase + { + [Test] + public void Test() + { + string json = @" +{ + ""Name"": ""MyName"", + ""ChildClassProp"": ""MyValue"", +}"; + + var record = JsonConvert.DeserializeObject(json); + Assert.AreEqual(null, record.Name); // Not set because doesn't have DataMember + Assert.AreEqual("MyValue", record.ChildClassProp); + } + + [DataContract] + public abstract class RecordBase + { + [JsonExtensionData] + protected IDictionary additionalData; + + public string Name { get; set; } + } + + [DataContract] + public class MyRecord : RecordBase + { + public MyRecord(string childClassProp) => ChildClassProp = childClassProp; + + [DataMember] + public string ChildClassProp { get; set; } + } + } +} +#endif diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2735.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2735.cs new file mode 100644 index 000000000..14a08b180 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Issues/Issue2735.cs @@ -0,0 +1,164 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !NET20 +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Tests.Documentation.Samples.Serializer; +#if DNXCORE50 +using System.Reflection; +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Issues +{ + [TestFixture] + public class Issue2735 : TestFixtureBase + { + [Test] + public void Test() + { + int maxDepth = 512; + + var currentFoo = new Foo(null); + + for (var i = 0; i < 100; i++) + { + currentFoo = new Foo(currentFoo); + } + + var fooBar = new FooBar(); + fooBar.AddFoo("main", currentFoo); + + var json = JsonConvert.SerializeObject(fooBar, SerializeSettings(maxDepth)); + + JsonConvert.DeserializeObject(json, DeserializeSettings(maxDepth)); + } + + [Test] + public void Test_Failure() + { + int maxDepth = 512; + + var currentFoo = new Foo(null); + + for (var i = 0; i < 600; i++) + { + currentFoo = new Foo(currentFoo); + } + + var fooBar = new FooBar(); + fooBar.AddFoo("main", currentFoo); + + var json = JsonConvert.SerializeObject(fooBar, SerializeSettings(maxDepth)); + + var ex = ExceptionAssert.Throws(() => JsonConvert.DeserializeObject(json, DeserializeSettings(maxDepth))); + Assert.IsTrue(ex.Message.StartsWith("The reader's MaxDepth of 512 has been exceeded.")); + } + + [Test] + public void Test_Failure2() + { + int maxDepth = 10; + + var currentFoo = new Foo(null); + + for (var i = 0; i < 20; i++) + { + currentFoo = new Foo(currentFoo); + } + + var fooBar = new FooBar(); + fooBar.AddFoo("main", currentFoo); + + var json = JsonConvert.SerializeObject(fooBar, SerializeSettings(maxDepth)); + + var ex = ExceptionAssert.Throws(() => JsonConvert.DeserializeObject(json, DeserializeSettings(maxDepth))); + Assert.IsTrue(ex.Message.StartsWith("The reader's MaxDepth of 10 has been exceeded.")); + } + + [Serializable] + public class FooBar : ISerializable + { + private Dictionary _myData = new Dictionary(); + + public IList FooList => _myData.Values.ToList(); + + public FooBar() + { + } + + public FooBar(SerializationInfo info, StreamingContext context) + { + _myData = (Dictionary)info.GetValue(nameof(_myData), typeof(Dictionary)); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue(nameof(_myData), _myData); + } + + public void AddFoo(string name, Foo myFoo) + { + _myData[name] = myFoo; + } + } + + public class Foo + { + public Guid Id { get; } + public Foo MyFoo { get; set; } + + public Foo(Foo myFoo) + { + MyFoo = myFoo; + Id = Guid.NewGuid(); + } + } + + private JsonSerializerSettings DeserializeSettings(int maxDepth) => new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.None, + MaxDepth = maxDepth + }; + + private JsonSerializerSettings SerializeSettings(int maxDepth) => new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.All, + MaxDepth = maxDepth + }; + } +} +#endif diff --git a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs index 9862161bf..2582f43a3 100644 --- a/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonConvertTest.cs @@ -30,7 +30,7 @@ using System.Globalization; using System.IO; using Newtonsoft.Json.Schema; -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Runtime.Serialization; @@ -792,13 +792,13 @@ public void WriteDateTime() Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + @")\/", result.MsDateUtc); - DateTime ticksLocal = new DateTime(634663873826822481, DateTimeKind.Local); + DateTime ticksLocal = new DateTime(636556897826822481, DateTimeKind.Local); localToUtcDate = ticksLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); result = TestDateTime("DateTime Local with ticks", ticksLocal); - Assert.AreEqual("2012-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); - Assert.AreEqual("2012-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); - Assert.AreEqual("2012-03-03T16:03:02.6822481", result.IsoDateUnspecified); + Assert.AreEqual("2018-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); + Assert.AreEqual("2018-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); + Assert.AreEqual("2018-03-03T16:03:02.6822481", result.IsoDateUnspecified); Assert.AreEqual(localToUtcDate, result.IsoDateUtc); Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); @@ -1139,7 +1139,7 @@ public void MaximumDateTimeMicrosoftDateFormatLength() writer.Flush(); } -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void IntegerLengthOverflows() { @@ -1563,14 +1563,15 @@ public class OverloadWithBaseType public int Overload { get; set; } } - [Test] - public void JsonConverterConstructor_OverloadsWithBaseTypes() - { - OverloadWithBaseType value = new OverloadWithBaseType(); - string json = JsonConvert.SerializeObject(value); + //[Test] + //[Ignore("https://github.com/dotnet/roslyn/issues/36974")] + //public void JsonConverterConstructor_OverloadsWithBaseTypes() + //{ + // OverloadWithBaseType value = new OverloadWithBaseType(); + // string json = JsonConvert.SerializeObject(value); - Assert.AreEqual("{\"Overload\":\"IList\"}", json); - } + // Assert.AreEqual("{\"Overload\":\"IList\"}", json); + //} [Test] diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingAsyncTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingAsyncTests.cs index fa2d9a500..91f8aa7fb 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingAsyncTests.cs @@ -27,7 +27,7 @@ using System; using System.Globalization; -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -593,7 +593,7 @@ await ExceptionAssert.ThrowsAsync(async () => } } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task ReadInt64OverflowAsync() { diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingTests.cs index 830deb559..0c82347d0 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ExceptionHandlingTests.cs @@ -28,7 +28,7 @@ using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json.Linq; -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -363,7 +363,8 @@ public void NullTextReader() new string[] { "Value cannot be null." + Environment.NewLine + "Parameter name: reader", - "Argument cannot be null." + Environment.NewLine + "Parameter name: reader" // Mono + "Argument cannot be null." + Environment.NewLine + "Parameter name: reader", // Mono + "Value cannot be null. (Parameter 'reader')" }); } @@ -616,7 +617,7 @@ public void ReadInt32Overflow_Negative() } } -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadInt64Overflow() { @@ -638,7 +639,7 @@ public void ReadInt64Overflow() } #endif -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadInt64Overflow_Negative() { diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/FloatTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/FloatTests.cs index 20d4c5eac..05874fe03 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/FloatTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/FloatTests.cs @@ -28,7 +28,7 @@ using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json.Linq; -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/MiscTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/MiscTests.cs index f25590e7f..ea46f8faa 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/MiscTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/MiscTests.cs @@ -28,7 +28,7 @@ using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json.Linq; -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseAsyncTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseAsyncTests.cs index e1a6c69ca..94a108875 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseAsyncTests.cs @@ -200,10 +200,22 @@ public async Task ParseDoublesAsync() Assert.AreEqual(Double.MinValue, reader.Value); reader = new JsonTextReader(new StringReader("1E+309")); +#if !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) await ExceptionAssert.ThrowsAsync(async () => await reader.ReadAsync(), "Input string '1E+309' is not a valid number. Path '', line 1, position 6."); +#else + Assert.IsTrue(await reader.ReadAsync()); + Assert.AreEqual(typeof(double), reader.ValueType); + Assert.AreEqual(Double.PositiveInfinity, reader.Value); +#endif reader = new JsonTextReader(new StringReader("-1E+5000")); +#if !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) await ExceptionAssert.ThrowsAsync(async () => await reader.ReadAsync(), "Input string '-1E+5000' is not a valid number. Path '', line 1, position 8."); +#else + Assert.IsTrue(await reader.ReadAsync()); + Assert.AreEqual(typeof(double), reader.ValueType); + Assert.AreEqual(Double.NegativeInfinity, reader.Value); +#endif reader = new JsonTextReader(new StringReader("5.1231231E")); await ExceptionAssert.ThrowsAsync(async () => await reader.ReadAsync(), "Input string '5.1231231E' is not a valid number. Path '', line 1, position 10."); diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseTests.cs index 5b18955ae..8347f9445 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ParseTests.cs @@ -28,7 +28,7 @@ using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json.Linq; -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -220,10 +220,22 @@ public void ParseDoubles() Assert.AreEqual(Double.MinValue, reader.Value); reader = new JsonTextReader(new StringReader("1E+309")); +#if !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) ExceptionAssert.Throws(() => reader.Read(), "Input string '1E+309' is not a valid number. Path '', line 1, position 6."); +#else + Assert.IsTrue(reader.Read()); + Assert.AreEqual(typeof(double), reader.ValueType); + Assert.AreEqual(Double.PositiveInfinity, reader.Value); +#endif reader = new JsonTextReader(new StringReader("-1E+5000")); +#if !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) ExceptionAssert.Throws(() => reader.Read(), "Input string '-1E+5000' is not a valid number. Path '', line 1, position 8."); +#else + Assert.IsTrue(reader.Read()); + Assert.AreEqual(typeof(double), reader.ValueType); + Assert.AreEqual(Double.NegativeInfinity, reader.Value); +#endif reader = new JsonTextReader(new StringReader("5.1231231E")); ExceptionAssert.Throws(() => reader.Read(), "Input string '5.1231231E' is not a valid number. Path '', line 1, position 10."); diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs index ccbe8fde2..5a99dd124 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadAsyncTests.cs @@ -28,7 +28,7 @@ using System; using System.Globalization; using Newtonsoft.Json.Linq; -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -84,11 +84,12 @@ public async Task ReadAsDecimalAsync_IntegerTooLarge_ThrowsJsonReaderException() await ExceptionAssert.ThrowsAsync( () => token.CreateReader().ReadAsDecimalAsync(), - "Could not convert to decimal: 1.79769313486232E+308. Path ''." + "Could not convert to decimal: 1.79769313486232E+308. Path ''.", + "Could not convert to decimal: 1.7976931348623157E+308. Path ''." ); } -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task ReadAsInt32Async_BigIntegerValue_Success() { @@ -131,7 +132,7 @@ await ExceptionAssert.ThrowsAsync(async () => "Unexpected character encountered while parsing value: u. Path '', line 1, position 1."); } -#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task ReadAsBooleanAsync() { @@ -1244,7 +1245,7 @@ second line third line", jsonTextReader.Value); } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task ReadBigIntegerAsync() { @@ -1775,6 +1776,45 @@ public async Task ThrowOnDuplicateKeysDeserializingAsync() JsonTextReader reader = new JsonTextReader(new StringReader(json)); await ExceptionAssert.ThrowsAsync(async () => await JToken.ReadFromAsync(reader, settings)); } + + [Test] + public async Task MaxDepth_GreaterThanDefaultAsync() + { + string json = GetNestedJson(150); + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.MaxDepth = 150; + + while (await reader.ReadAsync()) + { + } + } + + [Test] + public async Task MaxDepth_NullAsync() + { + string json = GetNestedJson(150); + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.MaxDepth = null; + + while (await reader.ReadAsync()) + { + } + } + + [Test] + public async Task MaxDepth_MaxValueAsync() + { + string json = GetNestedJson(150); + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.MaxDepth = int.MaxValue; + + while (await reader.ReadAsync()) + { + } + } } } #endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs index ce96f3d3e..c682bcc56 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextReaderTests/ReadTests.cs @@ -28,7 +28,7 @@ using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json.Linq; -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -89,11 +89,12 @@ public void ReadAsDecimal_IntegerTooLarge_ThrowsJsonReaderException() ExceptionAssert.Throws( () => token.CreateReader().ReadAsDecimal(), - "Could not convert to decimal: 1.79769313486232E+308. Path ''." + "Could not convert to decimal: 1.79769313486232E+308. Path ''.", + "Could not convert to decimal: 1.7976931348623157E+308. Path ''." ); } -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadAsInt32_BigIntegerValue_Success() { @@ -136,7 +137,7 @@ public void ReadAsInt32WithUndefined() "Unexpected character encountered while parsing value: u. Path '', line 1, position 1."); } -#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadAsBoolean() { @@ -1263,7 +1264,7 @@ second line -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadBigInteger() { @@ -1769,5 +1770,44 @@ public void ThrowOnDuplicateKeysDeserializing() JToken.ReadFrom(reader, settings); }); } + + [Test] + public void MaxDepth_GreaterThanDefault() + { + string json = GetNestedJson(150); + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.MaxDepth = 150; + + while (reader.Read()) + { + } + } + + [Test] + public void MaxDepth_Null() + { + string json = GetNestedJson(150); + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.MaxDepth = null; + + while (reader.Read()) + { + } + } + + [Test] + public void MaxDepth_MaxValue() + { + string json = GetNestedJson(150); + + JsonTextReader reader = new JsonTextReader(new StringReader(json)); + reader.MaxDepth = int.MaxValue; + + while (reader.Read()) + { + } + } } } diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterAsyncTests.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterAsyncTests.cs index 11b111dca..d4b93cfb3 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterAsyncTests.cs @@ -102,7 +102,7 @@ private async Task DoDelay(Task t) } } -#if !(NETSTANDARD1_0 || PORTABLE) || NETSTANDARD2_0 +#if !(NETSTANDARD1_0 || PORTABLE) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task WriteLazy() { @@ -370,7 +370,7 @@ public async Task CloseOutputAsync() Assert.IsTrue(ms.CanRead); } -#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task WriteIConvertableAsync() { @@ -1018,7 +1018,11 @@ public async Task WriteFloatingPointNumberAsync() await jsonWriter.WriteEndArrayAsync(); } +#if !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) Assert.AreEqual(@"[0.0,0.0,0.1,1.0,1.000001,1E-06,4.94065645841247E-324,Infinity,-Infinity,NaN,1.7976931348623157E+308,-1.7976931348623157E+308,Infinity,-Infinity,NaN]", sb.ToString()); +#else + Assert.AreEqual(@"[0.0,0.0,0.1,1.0,1.000001,1E-06,5E-324,Infinity,-Infinity,NaN,1.7976931348623157E+308,-1.7976931348623157E+308,Infinity,-Infinity,NaN]", sb.ToString()); +#endif } [Test] @@ -1094,7 +1098,7 @@ public async Task WriteTokenDirect_BadValueAsync() await ExceptionAssert.ThrowsAsync(async () => { await jsonWriter.WriteTokenAsync(JsonToken.Integer, "three"); }, "Input string was not in a correct format."); await ExceptionAssert.ThrowsAsync(async () => { await jsonWriter.WriteTokenAsync(JsonToken.Integer); }, @"Value cannot be null. -Parameter name: value"); +Parameter name: value", "Value cannot be null. (Parameter 'value')"); } } diff --git a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs index 570d66fb2..dcab597d8 100644 --- a/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/JsonTextWriterTest.cs @@ -136,7 +136,7 @@ public void BufferTest_WithError() Assert.AreEqual(1, arrayPool.FreeArrays.Count); } -#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || NET35 || NET40 || PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void BufferErroringWithInvalidSize() { @@ -225,7 +225,7 @@ public void CloseOutput() Assert.IsTrue(ms.CanRead); } -#if !(PORTABLE) || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void WriteIConvertable() { @@ -880,7 +880,12 @@ public void WriteFloatingPointNumber() jsonWriter.WriteEndArray(); } +#if !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) Assert.AreEqual(@"[0.0,0.0,0.1,1.0,1.000001,1E-06,4.94065645841247E-324,Infinity,-Infinity,NaN,1.7976931348623157E+308,-1.7976931348623157E+308,Infinity,-Infinity,NaN]", sb.ToString()); +#else + Assert.AreEqual(@"[0.0,0.0,0.1,1.0,1.000001,1E-06,5E-324,Infinity,-Infinity,NaN,1.7976931348623157E+308,-1.7976931348623157E+308,Infinity,-Infinity,NaN]", sb.ToString()); +#endif + } [Test] @@ -940,13 +945,15 @@ public void WriteTokenDirect() jsonWriter.WriteToken(JsonToken.StartArray); jsonWriter.WriteToken(JsonToken.Integer, 1); jsonWriter.WriteToken(JsonToken.StartObject); - jsonWriter.WriteToken(JsonToken.PropertyName, "string"); + jsonWriter.WriteToken(JsonToken.PropertyName, "integer"); jsonWriter.WriteToken(JsonToken.Integer, int.MaxValue); + jsonWriter.WriteToken(JsonToken.PropertyName, "null-string"); + jsonWriter.WriteToken(JsonToken.String, null); jsonWriter.WriteToken(JsonToken.EndObject); jsonWriter.WriteToken(JsonToken.EndArray); } - Assert.AreEqual(@"[1,{""string"":2147483647}]", sb.ToString()); + Assert.AreEqual(@"[1,{""integer"":2147483647,""null-string"":null}]", sb.ToString()); } [Test] @@ -962,7 +969,7 @@ public void WriteTokenDirect_BadValue() ExceptionAssert.Throws(() => { jsonWriter.WriteToken(JsonToken.Integer, "three"); }, "Input string was not in a correct format."); ExceptionAssert.Throws(() => { jsonWriter.WriteToken(JsonToken.Integer); }, @"Value cannot be null. -Parameter name: value"); +Parameter name: value", "Value cannot be null. (Parameter 'value')"); } } @@ -1212,7 +1219,7 @@ public void BuildStateArray() { JsonWriter.State[][] stateArray = JsonWriter.BuildStateArray(); - var valueStates = JsonWriter.StateArrayTempate[7]; + var valueStates = JsonWriter.StateArrayTemplate[7]; foreach (JsonToken valueToken in GetValues(typeof(JsonToken))) { diff --git a/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs index 33b607109..522429aed 100644 --- a/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs +++ b/Src/Newtonsoft.Json.Tests/JsonValidatingReaderTests.cs @@ -30,7 +30,7 @@ #if NET20 using Newtonsoft.Json.Utilities.LinqBridge; #endif -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -353,7 +353,7 @@ public void IntegerGreaterThanMaximumValue() Assert.IsNotNull(validationEventArgs); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void IntegerGreaterThanMaximumValue_BigInteger() { @@ -606,7 +606,7 @@ public void FloatDivisibleBy() Assert.IsNotNull(validationEventArgs); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void BigIntegerDivisibleBy_Success() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs index ff3657dcd..7a8eb44ee 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/AnnotationsTests.cs @@ -257,6 +257,186 @@ public void RemoveAnnotation_MultipleWithDifferentTypes_NonGeneric() Assert.AreEqual(new Uri("http://www.google.com/"), i); } + [Test] + public void AnnotationsAreCopied() + { + JObject o = new JObject(); + o.AddAnnotation("string!"); + AssertCloneCopy(o, "string!"); + + JProperty p = new JProperty("Name", "Content"); + p.AddAnnotation("string!"); + AssertCloneCopy(p, "string!"); + + JArray a = new JArray(); + a.AddAnnotation("string!"); + AssertCloneCopy(a, "string!"); + + JConstructor c = new JConstructor("Test"); + c.AddAnnotation("string!"); + AssertCloneCopy(c, "string!"); + + JValue v = new JValue(true); + v.AddAnnotation("string!"); + AssertCloneCopy(v, "string!"); + + JRaw r = new JRaw("raw"); + r.AddAnnotation("string!"); + AssertCloneCopy(r, "string!"); + } + + [Test] + public void MultipleAnnotationsAreCopied() + { + Version version = new Version(1, 2, 3, 4); + + JObject o = new JObject(); + o.AddAnnotation("string!"); + o.AddAnnotation(version); + + JObject o2 = (JObject)o.DeepClone(); + Assert.AreEqual("string!", o2.Annotation()); + Assert.AreEqual(version, o2.Annotation()); + + o2.RemoveAnnotations(); + Assert.AreEqual(1, o.Annotations().Count()); + Assert.AreEqual(0, o2.Annotations().Count()); + } + + [Test] + public void NestedAnnotationsAreCopied() + { + Version version = new Version(1, 2, 3, 4); + + JObject o = new JObject(); + o.AddAnnotation("string!"); + o.AddAnnotation(version); + + JValue v = new JValue(true); + v.AddAnnotation("string!"); + v.AddAnnotation(version); + + o["Item1"] = v; + + JObject o2 = (JObject)o.DeepClone(); + Assert.AreEqual("string!", o2.Annotation()); + Assert.AreEqual(version, o2.Annotation()); + + JValue v2 = (JValue)o2["Item1"]; + Assert.AreEqual("string!", v2.Annotation()); + Assert.AreEqual(version, v2.Annotation()); + } + + [Test] + public void NestedAnnotationsAreCopiedWithDefault() + { + Version version = new Version(1, 2, 3, 4); + JsonCloneSettings settings = new JsonCloneSettings(); + + JObject o = new JObject(); + o.AddAnnotation("string!"); + o.AddAnnotation(version); + + JValue v = new JValue(true); + v.AddAnnotation("string!"); + v.AddAnnotation(version); + + o["Item1"] = v; + + JObject o2 = (JObject)o.DeepClone(settings); + Assert.AreEqual("string!", o2.Annotation()); + Assert.AreEqual(version, o2.Annotation()); + + JValue v2 = (JValue)o2["Item1"]; + Assert.AreEqual("string!", v2.Annotation()); + Assert.AreEqual(version, v2.Annotation()); + } + + [Test] + public void NestedAnnotationsAreNotCopiedWithSettingsCopyAnnotationsFalse() + { + Version version = new Version(1, 2, 3, 4); + JsonCloneSettings settings = new JsonCloneSettings() { CopyAnnotations = false }; + + JObject o = new JObject(); + o.AddAnnotation("string!"); + o.AddAnnotation(version); + + JValue v = new JValue(true); + v.AddAnnotation("string!"); + v.AddAnnotation(version); + + o["Item1"] = v; + + JObject o2 = (JObject)o.DeepClone(settings); + Assert.IsNull(o2.Annotation()); + Assert.AreEqual(0, o2.Annotations().Count()); + + JValue v2 = (JValue)o2["Item1"]; + Assert.IsNull(v2.Annotation()); + Assert.AreEqual(0, v2.Annotations().Count()); + } + + private void AssertCloneCopy(JToken t, T annotation) where T : class + { + Assert.AreEqual(annotation, t.DeepClone().Annotation()); + } + + [Test] + public void MultipleAnnotationsAreNotCopiedWithSetting() + { + Version version = new Version(1, 2, 3, 4); + JsonCloneSettings settings = new JsonCloneSettings() { CopyAnnotations = false }; + + JObject o = new JObject(); + o.AddAnnotation("string!"); + o.AddAnnotation(version); + + JObject o2 = (JObject)o.DeepClone(settings); + Assert.IsNull(o2.Annotation()); + Assert.AreEqual(0, o2.Annotations().Count()); + + JArray a = new JArray(); + a.AddAnnotation("string!"); + a.AddAnnotation(version); + + JArray a2 = (JArray)a.DeepClone(settings); + Assert.IsNull(a2.Annotation()); + Assert.AreEqual(0, a2.Annotations().Count()); + + JProperty p = new JProperty("test"); + p.AddAnnotation("string!"); + p.AddAnnotation(version); + + JProperty p2 = (JProperty)p.DeepClone(settings); + Assert.IsNull(p2.Annotation()); + Assert.AreEqual(0, p2.Annotations().Count()); + + JRaw r = new JRaw("test"); + r.AddAnnotation("string!"); + r.AddAnnotation(version); + + JRaw r2 = (JRaw)r.DeepClone(settings); + Assert.IsNull(r2.Annotation()); + Assert.AreEqual(0, r2.Annotations().Count()); + + JConstructor c = new JConstructor("test"); + c.AddAnnotation("string!"); + c.AddAnnotation(version); + + JConstructor c2 = (JConstructor)c.DeepClone(settings); + Assert.IsNull(c2.Annotation()); + Assert.AreEqual(0, c2.Annotations().Count()); + + JValue v = new JValue("test"); + v.AddAnnotation("string!"); + v.AddAnnotation(version); + + JValue v2 = (JValue)v.DeepClone(settings); + Assert.IsNull(v2.Annotation()); + Assert.AreEqual(0, v2.Annotations().Count()); + } + #if !NET20 [Test] public void Example() diff --git a/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JPropertyDescriptorTests.cs b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JPropertyDescriptorTests.cs index bcbf661e4..72bea0682 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JPropertyDescriptorTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/ComponentModel/JPropertyDescriptorTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER #if DNXCORE50 using Xunit; using Test = Xunit.FactAttribute; diff --git a/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs b/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs index 0766b88dc..249147117 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/DynamicTests.cs @@ -29,7 +29,7 @@ using System.Collections.Generic; using System.Dynamic; using System.Linq; -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -257,7 +257,7 @@ public void JValueEquals() new JProperty("Uri", new Uri("http://json.codeplex.com/")), new JProperty("Guid", new Guid("EA27FE1D-0D80-44F2-BF34-4654156FA7AF")), new JProperty("TimeSpan", TimeSpan.FromDays(1)) -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER , new JProperty("BigInteger", BigInteger.Parse("1")) #endif ); @@ -290,7 +290,7 @@ public void JValueEquals() Assert.IsTrue(d.Decimal == 1.1m); Assert.IsTrue(d.Decimal != 1.0f); Assert.IsTrue(d.Decimal != 1.0d); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER Assert.IsTrue(d.Decimal > new BigInteger(0)); #endif @@ -306,11 +306,11 @@ public void JValueEquals() Assert.IsTrue(d.Float == 1.1m); Assert.IsTrue(d.Float != 1.0f); Assert.IsTrue(d.Float != 1.0d); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER Assert.IsTrue(d.Float > new BigInteger(0)); #endif -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER Assert.IsTrue(d.BigInteger == d.BigInteger); Assert.IsTrue(d.BigInteger > 0); Assert.IsTrue(d.BigInteger > 0.0m); @@ -366,7 +366,7 @@ public void JValueAddition() new JProperty("Uri", new Uri("http://json.codeplex.com/")), new JProperty("Guid", new Guid("EA27FE1D-0D80-44F2-BF34-4654156FA7AF")), new JProperty("TimeSpan", TimeSpan.FromDays(1)) -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER , new JProperty("BigInteger", new BigInteger(100)) #endif ); @@ -445,7 +445,7 @@ public void JValueAddition() r += 2; Assert.AreEqual(null, r.Value); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER r = d.BigInteger + null; Assert.AreEqual(null, r.Value); r += 2; @@ -524,7 +524,7 @@ public void JValueAddition() r -= 2; Assert.AreEqual(null, r.Value); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER r = d.BigInteger - null; Assert.AreEqual(null, r.Value); r -= 2; @@ -598,7 +598,7 @@ public void JValueAddition() r *= 2; Assert.AreEqual(null, r.Value); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER r = d.BigInteger * 1.1d; Assert.AreEqual(100m, (decimal)r); r *= 2; @@ -672,7 +672,7 @@ public void JValueAddition() r /= 2; Assert.AreEqual(null, r.Value); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER r = d.BigInteger / 1.1d; Assert.AreEqual(100m, (decimal)r); r /= 2; @@ -700,7 +700,7 @@ public void JValueToString() new JProperty("Uri", new Uri("http://json.codeplex.com/")), new JProperty("Guid", new Guid("EA27FE1D-0D80-44F2-BF34-4654156FA7AF")), new JProperty("TimeSpan", TimeSpan.FromDays(1)) -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER , new JProperty("BigInteger", new BigInteger(100)) #endif ); @@ -717,7 +717,7 @@ public void JValueToString() Assert.AreEqual("http://json.codeplex.com/", d.Uri.ToString()); Assert.AreEqual("ea27fe1d-0d80-44f2-bf34-4654156fa7af", d.Guid.ToString()); Assert.AreEqual("1.00:00:00", d.TimeSpan.ToString()); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER Assert.AreEqual("100", d.BigInteger.ToString()); #endif } @@ -801,7 +801,7 @@ public void JValueConvert() AssertValueConverted(null); AssertValueConverted(new Uri("http://json.codeplex.com/")); AssertValueConverted(null); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER AssertValueConverted(new BigInteger(100)); AssertValueConverted(null); #endif diff --git a/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs index 735ed36cc..2cb76c50a 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs @@ -127,8 +127,10 @@ public void GenericCollectionCopyToNullArrayShouldThrow() { JArray j = new JArray(); - ExceptionAssert.Throws(() => { ((ICollection)j).CopyTo(null, 0); }, @"Value cannot be null. -Parameter name: array"); + ExceptionAssert.Throws(() => { ((ICollection)j).CopyTo(null, 0); }, + @"Value cannot be null. +Parameter name: array", + "Value cannot be null. (Parameter 'array')"); } [Test] @@ -136,8 +138,10 @@ public void GenericCollectionCopyToNegativeArrayIndexShouldThrow() { JArray j = new JArray(); - ExceptionAssert.Throws(() => { ((ICollection)j).CopyTo(new JToken[1], -1); }, @"arrayIndex is less than 0. -Parameter name: arrayIndex"); + ExceptionAssert.Throws(() => { ((ICollection)j).CopyTo(new JToken[1], -1); }, + @"arrayIndex is less than 0. +Parameter name: arrayIndex", + "arrayIndex is less than 0. (Parameter 'arrayIndex')"); } [Test] @@ -232,8 +236,11 @@ public void RemoveAtOutOfRangeIndexShouldError() { JArray j = new JArray(); - ExceptionAssert.Throws(() => { j.RemoveAt(0); }, @"Index is equal to or greater than Count. -Parameter name: index"); + ExceptionAssert.Throws( + () => { j.RemoveAt(0); }, + @"Index is equal to or greater than Count. +Parameter name: index", + "Index is equal to or greater than Count. (Parameter 'index')"); } [Test] @@ -241,8 +248,11 @@ public void RemoveAtNegativeIndexShouldError() { JArray j = new JArray(); - ExceptionAssert.Throws(() => { j.RemoveAt(-1); }, @"Index is less than 0. -Parameter name: index"); + ExceptionAssert.Throws( + () => { j.RemoveAt(-1); }, + @"Index is less than 0. +Parameter name: index", + "Index is less than 0. (Parameter 'index')"); } [Test] @@ -320,8 +330,11 @@ public void InsertNegativeIndexShouldThrow() { JArray j = new JArray(); - ExceptionAssert.Throws(() => { j.Insert(-1, new JValue(1)); }, @"Index was out of range. Must be non-negative and less than the size of the collection. -Parameter name: index"); + ExceptionAssert.Throws( + () => { j.Insert(-1, new JValue(1)); }, + @"Index was out of range. Must be non-negative and less than the size of the collection. +Parameter name: index", + "Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')"); } [Test] @@ -329,8 +342,11 @@ public void InsertOutOfRangeIndexShouldThrow() { JArray j = new JArray(); - ExceptionAssert.Throws(() => { j.Insert(2, new JValue(1)); }, @"Index must be within the bounds of the List. -Parameter name: index"); + ExceptionAssert.Throws( + () => { j.Insert(2, new JValue(1)); }, + @"Index must be within the bounds of the List. +Parameter name: index", + "Index must be within the bounds of the List. (Parameter 'index')"); } [Test] @@ -431,7 +447,7 @@ public void Iterate() } } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ITypedListGetItemProperties() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs index 9afb4265f..94ab0ebed 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JObjectTests.cs @@ -58,7 +58,7 @@ namespace Newtonsoft.Json.Tests.Linq [TestFixture] public class JObjectTests : TestFixtureBase { -#if !(NET35 || NET20 || PORTABLE40) || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void EmbedJValueStringInNewJObject() { @@ -310,8 +310,10 @@ public void Contains() { contains = o.ContainsKey(null); Assert.AreEqual(false, contains); - }, @"Value cannot be null. -Parameter name: propertyName"); + }, + @"Value cannot be null. +Parameter name: propertyName", + "Value cannot be null. (Parameter 'propertyName')"); } [Test] @@ -359,8 +361,10 @@ public void GenericCollectionCopyToNullArrayShouldThrow() { JObject o = new JObject(); ((ICollection>)o).CopyTo(null, 0); - }, @"Value cannot be null. -Parameter name: array"); + }, + @"Value cannot be null. +Parameter name: array", + "Value cannot be null. (Parameter 'array')"); } [Test] @@ -370,8 +374,10 @@ public void GenericCollectionCopyToNegativeArrayIndexShouldThrow() { JObject o = new JObject(); ((ICollection>)o).CopyTo(new KeyValuePair[1], -1); - }, @"arrayIndex is less than 0. -Parameter name: arrayIndex"); + }, + @"arrayIndex is less than 0. +Parameter name: arrayIndex", + "arrayIndex is less than 0. (Parameter 'arrayIndex')"); } [Test] @@ -737,7 +743,7 @@ public void ReplaceJPropertyWithJPropertyWithSameName() Assert.AreEqual(p4, l[1]); } -#if !(NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void PropertyChanging() { @@ -1280,7 +1286,7 @@ public void GenericListJTokenSetItemAlreadyExists() }, "Can not add property Test3 to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object."); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void IBindingListSortDirection() { @@ -1433,7 +1439,7 @@ public void ITypedListGetItemProperties() ITypedList l = new JObject(p1, p2); PropertyDescriptorCollection propertyDescriptors = l.GetItemProperties(null); - Assert.IsNull(propertyDescriptors); + Assert.AreEqual(0, propertyDescriptors.Count); } [Test] @@ -1475,7 +1481,7 @@ public void ListChanged() } #endif -#if !(NET20 || NET35 || PORTABLE40) || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void CollectionChanged() { @@ -1652,7 +1658,7 @@ public void ParseMultipleProperties_ReplaceDuplicateSetting() Assert.AreEqual("Name2", value); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void WriteObjectNullDBNullValue() { @@ -1764,7 +1770,7 @@ public void LoadFromNestedObjectIncomplete() }, "Unexpected end of content while loading JObject. Path 'short.error.code', line 6, position 14."); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void GetProperties() { @@ -2089,7 +2095,7 @@ public void Parse_ExcessiveContent() "Additional text encountered after finished reading JSON content: [. Path '', line 3, position 0."); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void GetPropertyOwner_ReturnsJObject() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs index 64a422ee4..cb36de525 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JPropertyTests.cs @@ -61,7 +61,7 @@ public void NullValue() Assert.AreEqual(p, p.Value.Parent); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ListChanged() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JRawTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JRawTests.cs index cfeb102b3..57b7c3a88 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JRawTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JRawTests.cs @@ -52,7 +52,7 @@ public void RawEquals() public void RawClone() { JRaw r1 = new JRaw("raw1"); - JToken r2 = r1.CloneToken(); + JToken r2 = r1.DeepClone(); CustomAssert.IsInstanceOfType(typeof(JRaw), r2); } diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderAsyncTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderAsyncTests.cs index c394663e8..45ed6946b 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderAsyncTests.cs @@ -36,7 +36,7 @@ using NUnit.Framework; #endif using System.IO; -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using Newtonsoft.Json.Linq; @@ -48,7 +48,7 @@ namespace Newtonsoft.Json.Tests.Linq [TestFixture] public class JTokenReaderAsyncTests : TestFixtureBase { -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task ConvertBigIntegerToDoubleAsync() { @@ -757,7 +757,7 @@ public async Task ReadAsDouble_Integer_SuccessAsync() Assert.AreEqual(1d, await reader.ReadAsDoubleAsync()); } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task ReadAsBoolean_BigInteger_SuccessAsync() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs index 85c4feeaf..770c6b3a7 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenReaderTest.cs @@ -35,7 +35,7 @@ #endif using Newtonsoft.Json; using System.IO; -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using Newtonsoft.Json.Linq; @@ -47,7 +47,7 @@ namespace Newtonsoft.Json.Tests.Linq [TestFixture] public class JTokenReaderTest : TestFixtureBase { -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ConvertBigIntegerToDouble() { @@ -884,7 +884,7 @@ public void ReadAsDouble_Integer_Success() Assert.AreEqual(1d, reader.ReadAsDouble()); } -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadAsBoolean_BigInteger_Success() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs index d72dc8d56..84528822e 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenTests.cs @@ -25,7 +25,7 @@ using System; using System.Collections.Generic; -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -242,6 +242,27 @@ public void BeforeAfter() Assert.AreEqual(2, a[2].BeforeSelf().Count()); } + [Test] + public void BeforeSelf_NoParent_ReturnEmpty() + { + JObject o = new JObject(); + + List result = o.BeforeSelf().ToList(); + Assert.AreEqual(0, result.Count); + } + + [Test] + public void BeforeSelf_OnlyChild_ReturnEmpty() + { + JArray a = new JArray(); + JObject o = new JObject(); + a.Add(o); + + List result = o.BeforeSelf().ToList(); + Assert.AreEqual(0, result.Count); + } + +#nullable enable [Test] public void Casting() { @@ -253,44 +274,44 @@ public void Casting() Assert.AreEqual(new DateTimeOffset(2000, 12, 20, 0, 0, 0, TimeSpan.Zero), (DateTimeOffset)new JValue(new DateTime(2000, 12, 20, 0, 0, 0, DateTimeKind.Utc))); Assert.AreEqual(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero), (DateTimeOffset)new JValue(new DateTimeOffset(2000, 12, 20, 23, 50, 10, TimeSpan.Zero))); Assert.AreEqual(null, (DateTimeOffset?)new JValue((DateTimeOffset?)null)); - Assert.AreEqual(null, (DateTimeOffset?)(JValue)null); + Assert.AreEqual(null, (DateTimeOffset?)(JValue?)null); #endif Assert.AreEqual(true, (bool)new JValue(true)); Assert.AreEqual(true, (bool?)new JValue(true)); - Assert.AreEqual(null, (bool?)((JValue)null)); + Assert.AreEqual(null, (bool?)((JValue?)null)); Assert.AreEqual(null, (bool?)JValue.CreateNull()); Assert.AreEqual(10, (long)new JValue(10)); Assert.AreEqual(null, (long?)new JValue((long?)null)); - Assert.AreEqual(null, (long?)(JValue)null); + Assert.AreEqual(null, (long?)(JValue?)null); Assert.AreEqual(null, (int?)new JValue((int?)null)); - Assert.AreEqual(null, (int?)(JValue)null); + Assert.AreEqual(null, (int?)(JValue?)null); Assert.AreEqual(null, (DateTime?)new JValue((DateTime?)null)); - Assert.AreEqual(null, (DateTime?)(JValue)null); + Assert.AreEqual(null, (DateTime?)(JValue?)null); Assert.AreEqual(null, (short?)new JValue((short?)null)); - Assert.AreEqual(null, (short?)(JValue)null); + Assert.AreEqual(null, (short?)(JValue?)null); Assert.AreEqual(null, (float?)new JValue((float?)null)); - Assert.AreEqual(null, (float?)(JValue)null); + Assert.AreEqual(null, (float?)(JValue?)null); Assert.AreEqual(null, (double?)new JValue((double?)null)); - Assert.AreEqual(null, (double?)(JValue)null); + Assert.AreEqual(null, (double?)(JValue?)null); Assert.AreEqual(null, (decimal?)new JValue((decimal?)null)); - Assert.AreEqual(null, (decimal?)(JValue)null); + Assert.AreEqual(null, (decimal?)(JValue?)null); Assert.AreEqual(null, (uint?)new JValue((uint?)null)); - Assert.AreEqual(null, (uint?)(JValue)null); + Assert.AreEqual(null, (uint?)(JValue?)null); Assert.AreEqual(null, (sbyte?)new JValue((sbyte?)null)); - Assert.AreEqual(null, (sbyte?)(JValue)null); + Assert.AreEqual(null, (sbyte?)(JValue?)null); Assert.AreEqual(null, (byte?)new JValue((byte?)null)); - Assert.AreEqual(null, (byte?)(JValue)null); + Assert.AreEqual(null, (byte?)(JValue?)null); Assert.AreEqual(null, (ulong?)new JValue((ulong?)null)); - Assert.AreEqual(null, (ulong?)(JValue)null); + Assert.AreEqual(null, (ulong?)(JValue?)null); Assert.AreEqual(null, (uint?)new JValue((uint?)null)); - Assert.AreEqual(null, (uint?)(JValue)null); + Assert.AreEqual(null, (uint?)(JValue?)null); Assert.AreEqual(11.1f, (float)new JValue(11.1)); Assert.AreEqual(float.MinValue, (float)new JValue(float.MinValue)); Assert.AreEqual(1.1, (double)new JValue(1.1)); Assert.AreEqual(uint.MaxValue, (uint)new JValue(uint.MaxValue)); Assert.AreEqual(ulong.MaxValue, (ulong)new JValue(ulong.MaxValue)); Assert.AreEqual(ulong.MaxValue, (ulong)new JProperty("Test", new JValue(ulong.MaxValue))); - Assert.AreEqual(null, (string)new JValue((string)null)); + Assert.AreEqual(null, (string?)new JValue((string?)null)); Assert.AreEqual(5m, (decimal)(new JValue(5L))); Assert.AreEqual(5m, (decimal?)(new JValue(5L))); Assert.AreEqual(5f, (float)(new JValue(5L))); @@ -302,15 +323,15 @@ public void Casting() Assert.AreEqual(null, (sbyte?)JValue.CreateNull()); - Assert.AreEqual("1", (string)(new JValue(1))); - Assert.AreEqual("1", (string)(new JValue(1.0))); - Assert.AreEqual("1.0", (string)(new JValue(1.0m))); - Assert.AreEqual("True", (string)(new JValue(true))); - Assert.AreEqual(null, (string)(JValue.CreateNull())); - Assert.AreEqual(null, (string)(JValue)null); - Assert.AreEqual("12/12/2000 12:12:12", (string)(new JValue(new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc)))); + Assert.AreEqual("1", (string?)(new JValue(1))); + Assert.AreEqual("1", (string?)(new JValue(1.0))); + Assert.AreEqual("1.0", (string?)(new JValue(1.0m))); + Assert.AreEqual("True", (string?)(new JValue(true))); + Assert.AreEqual(null, (string?)(JValue.CreateNull())); + Assert.AreEqual(null, (string?)(JValue?)null); + Assert.AreEqual("12/12/2000 12:12:12", (string?)(new JValue(new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc)))); #if !NET20 - Assert.AreEqual("12/12/2000 12:12:12 +00:00", (string)(new JValue(new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.Zero)))); + Assert.AreEqual("12/12/2000 12:12:12 +00:00", (string?)(new JValue(new DateTimeOffset(2000, 12, 12, 12, 12, 12, TimeSpan.Zero)))); #endif Assert.AreEqual(true, (bool)(new JValue(1))); Assert.AreEqual(true, (bool)(new JValue(1.0))); @@ -327,50 +348,50 @@ public void Casting() Assert.AreEqual(1m, (decimal)(new JValue("1"))); Assert.AreEqual(1m, (decimal)(new JValue(true))); Assert.AreEqual(TimeSpan.FromMinutes(1), (TimeSpan)(new JValue(TimeSpan.FromMinutes(1)))); - Assert.AreEqual("00:01:00", (string)(new JValue(TimeSpan.FromMinutes(1)))); + Assert.AreEqual("00:01:00", (string?)(new JValue(TimeSpan.FromMinutes(1)))); Assert.AreEqual(TimeSpan.FromMinutes(1), (TimeSpan)(new JValue("00:01:00"))); - Assert.AreEqual("46efe013-b56a-4e83-99e4-4dce7678a5bc", (string)(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC")))); - Assert.AreEqual("http://www.google.com/", (string)(new JValue(new Uri("http://www.google.com")))); + Assert.AreEqual("46efe013-b56a-4e83-99e4-4dce7678a5bc", (string?)(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC")))); + Assert.AreEqual("http://www.google.com/", (string?)(new JValue(new Uri("http://www.google.com")))); Assert.AreEqual(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"), (Guid)(new JValue("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"))); Assert.AreEqual(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"), (Guid)(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC")))); - Assert.AreEqual(new Uri("http://www.google.com"), (Uri)(new JValue("http://www.google.com"))); - Assert.AreEqual(new Uri("http://www.google.com"), (Uri)(new JValue(new Uri("http://www.google.com")))); - Assert.AreEqual(null, (Uri)(JValue.CreateNull())); - Assert.AreEqual(Convert.ToBase64String(Encoding.UTF8.GetBytes("hi")), (string)(new JValue(Encoding.UTF8.GetBytes("hi")))); - CollectionAssert.AreEquivalent((byte[])Encoding.UTF8.GetBytes("hi"), (byte[])(new JValue(Convert.ToBase64String(Encoding.UTF8.GetBytes("hi"))))); + Assert.AreEqual(new Uri("http://www.google.com"), (Uri?)(new JValue("http://www.google.com"))); + Assert.AreEqual(new Uri("http://www.google.com"), (Uri?)(new JValue(new Uri("http://www.google.com")))); + Assert.AreEqual(null, (Uri?)(JValue.CreateNull())); + Assert.AreEqual(Convert.ToBase64String(Encoding.UTF8.GetBytes("hi")), (string?)(new JValue(Encoding.UTF8.GetBytes("hi")))); + CollectionAssert.AreEquivalent((byte[])Encoding.UTF8.GetBytes("hi"), (byte[]?)(new JValue(Convert.ToBase64String(Encoding.UTF8.GetBytes("hi"))))); Assert.AreEqual(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"), (Guid)(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC").ToByteArray()))); Assert.AreEqual(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"), (Guid?)(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC").ToByteArray()))); Assert.AreEqual((sbyte?)1, (sbyte?)(new JValue((short?)1))); - Assert.AreEqual(null, (Uri)(JValue)null); - Assert.AreEqual(null, (int?)(JValue)null); - Assert.AreEqual(null, (uint?)(JValue)null); - Assert.AreEqual(null, (Guid?)(JValue)null); - Assert.AreEqual(null, (TimeSpan?)(JValue)null); - Assert.AreEqual(null, (byte[])(JValue)null); - Assert.AreEqual(null, (bool?)(JValue)null); - Assert.AreEqual(null, (char?)(JValue)null); - Assert.AreEqual(null, (DateTime?)(JValue)null); + Assert.AreEqual(null, (Uri?)(JValue?)null); + Assert.AreEqual(null, (int?)(JValue?)null); + Assert.AreEqual(null, (uint?)(JValue?)null); + Assert.AreEqual(null, (Guid?)(JValue?)null); + Assert.AreEqual(null, (TimeSpan?)(JValue?)null); + Assert.AreEqual(null, (byte[]?)(JValue?)null); + Assert.AreEqual(null, (bool?)(JValue?)null); + Assert.AreEqual(null, (char?)(JValue?)null); + Assert.AreEqual(null, (DateTime?)(JValue?)null); #if !NET20 - Assert.AreEqual(null, (DateTimeOffset?)(JValue)null); + Assert.AreEqual(null, (DateTimeOffset?)(JValue?)null); #endif - Assert.AreEqual(null, (short?)(JValue)null); - Assert.AreEqual(null, (ushort?)(JValue)null); - Assert.AreEqual(null, (byte?)(JValue)null); - Assert.AreEqual(null, (byte?)(JValue)null); - Assert.AreEqual(null, (sbyte?)(JValue)null); - Assert.AreEqual(null, (sbyte?)(JValue)null); - Assert.AreEqual(null, (long?)(JValue)null); - Assert.AreEqual(null, (ulong?)(JValue)null); - Assert.AreEqual(null, (double?)(JValue)null); - Assert.AreEqual(null, (float?)(JValue)null); + Assert.AreEqual(null, (short?)(JValue?)null); + Assert.AreEqual(null, (ushort?)(JValue?)null); + Assert.AreEqual(null, (byte?)(JValue?)null); + Assert.AreEqual(null, (byte?)(JValue?)null); + Assert.AreEqual(null, (sbyte?)(JValue?)null); + Assert.AreEqual(null, (sbyte?)(JValue?)null); + Assert.AreEqual(null, (long?)(JValue?)null); + Assert.AreEqual(null, (ulong?)(JValue?)null); + Assert.AreEqual(null, (double?)(JValue?)null); + Assert.AreEqual(null, (float?)(JValue?)null); byte[] data = new byte[0]; - Assert.AreEqual(data, (byte[])(new JValue(data))); + Assert.AreEqual(data, (byte[]?)(new JValue(data))); Assert.AreEqual(5, (int)(new JValue(StringComparison.OrdinalIgnoreCase))); -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER string bigIntegerText = "1234567899999999999999999999999999999999999999999999999999999999999990"; Assert.AreEqual(BigInteger.Parse(bigIntegerText), (new JValue(BigInteger.Parse(bigIntegerText))).Value); @@ -384,19 +405,20 @@ public void Casting() Assert.AreEqual(new BigInteger(123), (new JValue(123)).ToObject()); Assert.AreEqual(null, (JValue.CreateNull()).ToObject()); - byte[] intData = BigInteger.Parse(bigIntegerText).ToByteArray(); + byte[]? intData = BigInteger.Parse(bigIntegerText).ToByteArray(); Assert.AreEqual(BigInteger.Parse(bigIntegerText), (new JValue(intData)).ToObject()); Assert.AreEqual(4.0d, (double)(new JValue(new BigInteger(4.5d)))); Assert.AreEqual(true, (bool)(new JValue(new BigInteger(1)))); Assert.AreEqual(long.MaxValue, (long)(new JValue(new BigInteger(long.MaxValue)))); Assert.AreEqual(long.MaxValue, (long)(new JValue(new BigInteger(new byte[] { 255, 255, 255, 255, 255, 255, 255, 127 })))); - Assert.AreEqual("9223372036854775807", (string)(new JValue(new BigInteger(long.MaxValue)))); + Assert.AreEqual("9223372036854775807", (string?)(new JValue(new BigInteger(long.MaxValue)))); - intData = (byte[])(new JValue(new BigInteger(long.MaxValue))); + intData = (byte[]?)new JValue(new BigInteger(long.MaxValue)); CollectionAssert.AreEqual(new byte[] { 255, 255, 255, 255, 255, 255, 255, 127 }, intData); #endif } +#nullable disable [Test] public void FailedCasting() @@ -450,7 +472,7 @@ public void FailedCasting() #endif ExceptionAssert.Throws(() => { var i = (Uri)new JValue(true); }, "Can not convert Boolean to Uri."); -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER ExceptionAssert.Throws(() => { var i = (new JValue(new Uri("http://www.google.com"))).ToObject(); }, "Can not convert Uri to BigInteger."); ExceptionAssert.Throws(() => { var i = (JValue.CreateNull()).ToObject(); }, "Can not convert Null to BigInteger."); ExceptionAssert.Throws(() => { var i = (new JValue(Guid.NewGuid())).ToObject(); }, "Can not convert Guid to BigInteger."); @@ -467,7 +489,7 @@ public void FailedCasting() [Test] public void ToObject() { -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER Assert.AreEqual((BigInteger)1, (new JValue(1).ToObject(typeof(BigInteger)))); Assert.AreEqual((BigInteger)1, (new JValue(1).ToObject(typeof(BigInteger?)))); Assert.AreEqual((BigInteger?)null, (JValue.CreateNull().ToObject(typeof(BigInteger?)))); @@ -516,6 +538,7 @@ public void ToObject() Assert.AreEqual(null, (JValue.CreateNull().ToObject(typeof(StringComparison?)))); } +#nullable enable [Test] public void ImplicitCastingTo() { @@ -525,7 +548,7 @@ public void ImplicitCastingTo() Assert.IsTrue(JToken.DeepEquals(new JValue((DateTimeOffset?)null), (JValue)(DateTimeOffset?)null)); #endif -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER // had to remove implicit casting to avoid user reference to System.Numerics.dll Assert.IsTrue(JToken.DeepEquals(new JValue(new BigInteger(1)), new JValue(new BigInteger(1)))); Assert.IsTrue(JToken.DeepEquals(new JValue((BigInteger?)null), new JValue((BigInteger?)null))); @@ -557,7 +580,7 @@ public void ImplicitCastingTo() Assert.IsTrue(JToken.DeepEquals(new JValue(uint.MaxValue), (JValue)uint.MaxValue)); Assert.IsTrue(JToken.DeepEquals(new JValue(ulong.MaxValue), (JValue)ulong.MaxValue)); Assert.IsTrue(JToken.DeepEquals(new JValue(ulong.MinValue), (JValue)ulong.MinValue)); - Assert.IsTrue(JToken.DeepEquals(new JValue((string)null), (JValue)(string)null)); + Assert.IsTrue(JToken.DeepEquals(new JValue((string?)null), (JValue)(string?)null)); Assert.IsTrue(JToken.DeepEquals(new JValue((DateTime?)null), (JValue)(DateTime?)null)); Assert.IsTrue(JToken.DeepEquals(new JValue(decimal.MaxValue), (JValue)decimal.MaxValue)); Assert.IsTrue(JToken.DeepEquals(new JValue(decimal.MaxValue), (JValue)(decimal?)decimal.MaxValue)); @@ -567,7 +590,7 @@ public void ImplicitCastingTo() Assert.IsTrue(JToken.DeepEquals(JValue.CreateNull(), (JValue)(double?)null)); Assert.IsFalse(JToken.DeepEquals(new JValue(true), (JValue)(bool?)null)); - Assert.IsFalse(JToken.DeepEquals(JValue.CreateNull(), (JValue)(object)null)); + Assert.IsFalse(JToken.DeepEquals(JValue.CreateNull(), (JValue?)(object?)null)); byte[] emptyData = new byte[0]; Assert.IsTrue(JToken.DeepEquals(new JValue(emptyData), (JValue)emptyData)); @@ -579,9 +602,10 @@ public void ImplicitCastingTo() Assert.IsTrue(JToken.DeepEquals(new JValue(TimeSpan.FromMinutes(1)), (JValue)(TimeSpan?)TimeSpan.FromMinutes(1))); Assert.IsTrue(JToken.DeepEquals(new JValue(new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC")), (JValue)new Guid("46EFE013-B56A-4E83-99E4-4DCE7678A5BC"))); Assert.IsTrue(JToken.DeepEquals(new JValue(new Uri("http://www.google.com")), (JValue)new Uri("http://www.google.com"))); - Assert.IsTrue(JToken.DeepEquals(JValue.CreateNull(), (JValue)(Uri)null)); + Assert.IsTrue(JToken.DeepEquals(JValue.CreateNull(), (JValue)(Uri?)null)); Assert.IsTrue(JToken.DeepEquals(JValue.CreateNull(), (JValue)(Guid?)null)); } +#nullable disable [Test] public void Root() @@ -1148,7 +1172,7 @@ public void DeepClone() Assert.IsTrue(a.DeepEquals(a2)); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void Clone() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterAsyncTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterAsyncTests.cs index 92e242376..a87ae5e78 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterAsyncTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterAsyncTests.cs @@ -26,7 +26,7 @@ #if !(NET20 || NET35 || NET40 || PORTABLE40) using System; -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -115,7 +115,7 @@ public async Task StateAsync() await jsonWriter.WriteValueAsync("DVD read/writer"); Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER await jsonWriter.WriteValueAsync(new BigInteger(123)); Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); #endif @@ -167,7 +167,7 @@ public async Task CurrentTokenAsync() Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); Assert.AreEqual(a[a.Count - 1], jsonWriter.CurrentToken); -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER await jsonWriter.WriteValueAsync(new BigInteger(123)); Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); Assert.AreEqual(a[a.Count - 1], jsonWriter.CurrentToken); @@ -200,7 +200,7 @@ public async Task WriteCommentAsync() /*fail*/]", writer.Token.ToString()); } -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public async Task WriteBigIntegerAsync() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs index d8d7dbe5f..3c3df235c 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JTokenWriterTest.cs @@ -25,7 +25,7 @@ using System; using System.Collections.Generic; -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -120,7 +120,7 @@ public void State() jsonWriter.WriteValue("DVD read/writer"); Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER jsonWriter.WriteValue(new BigInteger(123)); Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); #endif @@ -172,7 +172,7 @@ public void CurrentToken() Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); Assert.AreEqual(a[a.Count - 1], jsonWriter.CurrentToken); -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER jsonWriter.WriteValue(new BigInteger(123)); Assert.AreEqual(WriteState.Array, jsonWriter.WriteState); Assert.AreEqual(a[a.Count - 1], jsonWriter.CurrentToken); @@ -205,7 +205,7 @@ public void WriteComment() /*fail*/]", writer.Token.ToString()); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void WriteBigInteger() { @@ -392,5 +392,28 @@ public void DateTimeZoneHandling() Assert.AreEqual(new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc), dt); } + + [Test] + public void WriteTokenDirect() + { + JToken token; + + using (JTokenWriter jsonWriter = new JTokenWriter()) + { + jsonWriter.WriteToken(JsonToken.StartArray); + jsonWriter.WriteToken(JsonToken.Integer, 1); + jsonWriter.WriteToken(JsonToken.StartObject); + jsonWriter.WriteToken(JsonToken.PropertyName, "integer"); + jsonWriter.WriteToken(JsonToken.Integer, int.MaxValue); + jsonWriter.WriteToken(JsonToken.PropertyName, "null-string"); + jsonWriter.WriteToken(JsonToken.String, null); + jsonWriter.WriteToken(JsonToken.EndObject); + jsonWriter.WriteToken(JsonToken.EndArray); + + token = jsonWriter.Token; + } + + Assert.AreEqual(@"[1,{""integer"":2147483647,""null-string"":null}]", token.ToString(Formatting.None)); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs index 57add05ef..4eae2611d 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JValueTests.cs @@ -28,7 +28,7 @@ using System.IO; using System.Runtime.Serialization; using Newtonsoft.Json.Tests.TestObjects; -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Text; @@ -179,7 +179,7 @@ public void ChangeValue() Assert.AreEqual(g, v.Value); Assert.AreEqual(JTokenType.Guid, v.Type); -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER BigInteger i = BigInteger.Parse("123456789999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999990"); v.Value = i; Assert.AreEqual(i, v.Value); @@ -239,13 +239,13 @@ public void JValueToString() v = new JValue(new Guid("B282ADE7-C520-496C-A448-4084F6803DE5")); Assert.AreEqual("b282ade7-c520-496c-a448-4084f6803de5", v.ToString(null, CultureInfo.InvariantCulture)); -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER v = new JValue(BigInteger.Parse("123456789999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999990")); Assert.AreEqual("123456789999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999990", v.ToString(null, CultureInfo.InvariantCulture)); #endif } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void JValueParse() { @@ -256,7 +256,7 @@ public void JValueParse() } #endif -#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void JValueIConvertable() { @@ -505,7 +505,7 @@ public void ReadDatesAsDateTimeOffsetViaJsonConvert() } #endif -#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ConvertsToBoolean() { @@ -524,7 +524,7 @@ public void ConvertsToInt32() Assert.AreEqual(Int32.MaxValue, Convert.ToInt32(new JValue(Int32.MaxValue))); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ConvertsToInt32_BigInteger() { @@ -686,7 +686,7 @@ public void GetTypeCode() v = new JValue(new Uri("http://www.google.com")); Assert.AreEqual(TypeCode.Object, v.GetTypeCode()); -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER v = new JValue(new BigInteger(3)); Assert.AreEqual(TypeCode.Object, v.GetTypeCode()); #endif @@ -705,7 +705,7 @@ public void ToType() int i = (int)v.ToType(typeof(int), CultureInfo.InvariantCulture); Assert.AreEqual(9, i); -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER BigInteger bi = (BigInteger)v.ToType(typeof(BigInteger), CultureInfo.InvariantCulture); Assert.AreEqual(new BigInteger(9), bi); #endif @@ -720,7 +720,7 @@ public void ToStringFormat() Assert.AreEqual("2013", v.ToString("yyyy")); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ToStringNewTypes() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs index bb781a546..81ec02411 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/JPathExecuteTests.cs @@ -26,11 +26,14 @@ using System; using System.Collections.Generic; using System.Text; -#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using Newtonsoft.Json.Linq.JsonPath; using Newtonsoft.Json.Tests.Bson; +#if HAVE_REGEX_TIMEOUTS +using System.Text.RegularExpressions; +#endif #if DNXCORE50 using Xunit; using Test = Xunit.FactAttribute; @@ -44,7 +47,6 @@ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Newtonsoft.Json.Tests.Linq.JsonPath @@ -71,6 +73,27 @@ public void GreaterThanIssue1518() Assert.AreEqual(jObj, dd); } +#if HAVE_REGEX_TIMEOUTS + [Test] + public void BacktrackingRegex_SingleMatch_TimeoutRespected() + { + const string RegexBacktrackingPattern = "(?(.*?))[|].*(?(.*?))[|].*(?(.*?))[|].*(?[1-3])[|].*(?(.*?))[|].*[|].*[|].*(?(.*?))[|].*[|].*(?(.*?))[|].*(?(.*))"; + + var regexBacktrackingData = new JArray(); + regexBacktrackingData.Add(new JObject(new JProperty("b", @"15/04/2020 8:18:03 PM|1|System.String[]|3|Libero eligendi magnam ut inventore.. Quaerat et sit voluptatibus repellendus blanditiis aliquam ut.. Quidem qui ut sint in ex et tempore.|||.\iste.cpp||46018|-1"))); + + ExceptionAssert.Throws(() => + { + regexBacktrackingData.SelectTokens( + $"[?(@.b =~ /{RegexBacktrackingPattern}/)]", + new JsonSelectSettings + { + RegexMatchTimeout = TimeSpan.FromSeconds(0.01) + }).ToArray(); + }); + } +#endif + [Test] public void GreaterThanWithIntegerParameterAndStringValue() { @@ -958,7 +981,7 @@ public void LesserQuery_ValueFirst() Assert.IsTrue(JToken.DeepEquals(new JObject(new JProperty("hi", 3)), t[1])); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void GreaterQueryBigInteger() { @@ -1489,6 +1512,23 @@ public void IdentityOperator() Assert.AreEqual("String", mustBeString2.Single()); } + [Test] + public void QueryWithEscapedPath() + { + JToken t = JToken.Parse(@"{ +""Property"": [ + { + ""@Name"": ""x"", + ""@Value"": ""y"", + ""@Type"": ""FindMe"" + } + ] +}"); + + var tokens = t.SelectTokens("$..[?(@.['@Type'] == 'FindMe')]").ToList(); + Assert.AreEqual(1, tokens.Count); + } + [Test] public void Equals_FloatWithInt() { diff --git a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs index cdb3db070..edabea57c 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JsonPath/QueryExpressionTests.cs @@ -45,33 +45,12 @@ public class QueryExpressionTests : TestFixtureBase [Test] public void AndExpressionTest() { - CompositeExpression compositeExpression = new CompositeExpression + CompositeExpression compositeExpression = new CompositeExpression(QueryOperator.And) { - Operator = QueryOperator.And, Expressions = new List { - new BooleanQueryExpression - { - Operator = QueryOperator.Exists, - Left = new List - { - new FieldFilter - { - Name = "FirstName" - } - } - }, - new BooleanQueryExpression - { - Operator = QueryOperator.Exists, - Left = new List - { - new FieldFilter - { - Name = "LastName" - } - } - } + new BooleanQueryExpression(QueryOperator.Exists, new List { new FieldFilter("FirstName") }, null), + new BooleanQueryExpression(QueryOperator.Exists, new List { new FieldFilter("LastName") }, null) } }; @@ -103,33 +82,12 @@ public void AndExpressionTest() [Test] public void OrExpressionTest() { - CompositeExpression compositeExpression = new CompositeExpression + CompositeExpression compositeExpression = new CompositeExpression(QueryOperator.Or) { - Operator = QueryOperator.Or, Expressions = new List { - new BooleanQueryExpression - { - Operator = QueryOperator.Exists, - Left = new List - { - new FieldFilter - { - Name = "FirstName" - } - } - }, - new BooleanQueryExpression - { - Operator = QueryOperator.Exists, - Left = new List - { - new FieldFilter - { - Name = "LastName" - } - } - } + new BooleanQueryExpression(QueryOperator.Exists, new List { new FieldFilter("FirstName") }, null), + new BooleanQueryExpression(QueryOperator.Exists, new List { new FieldFilter("LastName") }, null) } }; @@ -161,30 +119,14 @@ public void OrExpressionTest() [Test] public void BooleanExpressionTest_RegexEqualsOperator() { - BooleanQueryExpression e1 = new BooleanQueryExpression - { - Operator = QueryOperator.RegexEquals, - Right = new JValue("/foo.*d/"), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e1 = new BooleanQueryExpression(QueryOperator.RegexEquals, new List { new ArrayIndexFilter() }, new JValue("/foo.*d/")); Assert.IsTrue(e1.IsMatch(null, new JArray("food"))); Assert.IsTrue(e1.IsMatch(null, new JArray("fooood and drink"))); Assert.IsFalse(e1.IsMatch(null, new JArray("FOOD"))); Assert.IsFalse(e1.IsMatch(null, new JArray("foo", "foog", "good"))); - BooleanQueryExpression e2 = new BooleanQueryExpression - { - Operator = QueryOperator.RegexEquals, - Right = new JValue("/Foo.*d/i"), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e2 = new BooleanQueryExpression(QueryOperator.RegexEquals, new List { new ArrayIndexFilter() }, new JValue("/Foo.*d/i")); Assert.IsTrue(e2.IsMatch(null, new JArray("food"))); Assert.IsTrue(e2.IsMatch(null, new JArray("fooood and drink"))); @@ -195,28 +137,12 @@ public void BooleanExpressionTest_RegexEqualsOperator() [Test] public void BooleanExpressionTest_RegexEqualsOperator_CornerCase() { - BooleanQueryExpression e1 = new BooleanQueryExpression - { - Operator = QueryOperator.RegexEquals, - Right = new JValue("/// comment/"), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e1 = new BooleanQueryExpression(QueryOperator.RegexEquals, new List { new ArrayIndexFilter() }, new JValue("/// comment/")); Assert.IsTrue(e1.IsMatch(null, new JArray("// comment"))); Assert.IsFalse(e1.IsMatch(null, new JArray("//comment", "/ comment"))); - BooleanQueryExpression e2 = new BooleanQueryExpression - { - Operator = QueryOperator.RegexEquals, - Right = new JValue("/.*/i"), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e2 = new BooleanQueryExpression(QueryOperator.RegexEquals, new List { new ArrayIndexFilter() }, new JValue("/.*/i")); Assert.IsTrue(e2.IsMatch(null, new JArray("Test", ""))); Assert.IsFalse(e2.IsMatch(null, new JArray("Test"))); @@ -225,15 +151,7 @@ public void BooleanExpressionTest_RegexEqualsOperator_CornerCase() [Test] public void BooleanExpressionTest() { - BooleanQueryExpression e1 = new BooleanQueryExpression - { - Operator = QueryOperator.LessThan, - Right = new JValue(3), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e1 = new BooleanQueryExpression(QueryOperator.LessThan, new List { new ArrayIndexFilter() }, new JValue(3)); Assert.IsTrue(e1.IsMatch(null, new JArray(1, 2, 3, 4, 5))); Assert.IsTrue(e1.IsMatch(null, new JArray(2, 3, 4, 5))); @@ -241,15 +159,7 @@ public void BooleanExpressionTest() Assert.IsFalse(e1.IsMatch(null, new JArray(4, 5))); Assert.IsFalse(e1.IsMatch(null, new JArray("11", 5))); - BooleanQueryExpression e2 = new BooleanQueryExpression - { - Operator = QueryOperator.LessThanOrEquals, - Right = new JValue(3), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e2 = new BooleanQueryExpression(QueryOperator.LessThanOrEquals, new List { new ArrayIndexFilter() }, new JValue(3)); Assert.IsTrue(e2.IsMatch(null, new JArray(1, 2, 3, 4, 5))); Assert.IsTrue(e2.IsMatch(null, new JArray(2, 3, 4, 5))); @@ -261,15 +171,7 @@ public void BooleanExpressionTest() [Test] public void BooleanExpressionTest_GreaterThanOperator() { - BooleanQueryExpression e1 = new BooleanQueryExpression - { - Operator = QueryOperator.GreaterThan, - Right = new JValue(3), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e1 = new BooleanQueryExpression(QueryOperator.GreaterThan, new List { new ArrayIndexFilter() }, new JValue(3)); Assert.IsTrue(e1.IsMatch(null, new JArray("2", "26"))); Assert.IsTrue(e1.IsMatch(null, new JArray(2, 26))); @@ -280,15 +182,7 @@ public void BooleanExpressionTest_GreaterThanOperator() [Test] public void BooleanExpressionTest_GreaterThanOrEqualsOperator() { - BooleanQueryExpression e1 = new BooleanQueryExpression - { - Operator = QueryOperator.GreaterThanOrEquals, - Right = new JValue(3), - Left = new List - { - new ArrayIndexFilter() - } - }; + BooleanQueryExpression e1 = new BooleanQueryExpression(QueryOperator.GreaterThanOrEquals, new List { new ArrayIndexFilter() }, new JValue(3)); Assert.IsTrue(e1.IsMatch(null, new JArray("2", "26"))); Assert.IsTrue(e1.IsMatch(null, new JArray(2, 26))); diff --git a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs index c3e706545..d22262023 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/LinqToJsonTest.cs @@ -62,7 +62,7 @@ public void EscapedQuotePath() Assert.AreEqual(@"['We\'re offline!']", v.Path); } -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER public class DemoClass { public decimal maxValue; diff --git a/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs b/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs index 6c86b8a38..db660052d 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/MergeTests.cs @@ -46,6 +46,74 @@ namespace Newtonsoft.Json.Tests.Linq [TestFixture] public class MergeTests : TestFixtureBase { + [Test] + public void MergeInvalidObject() + { + var a = new JObject(); + + ExceptionAssert.Throws( + () => a.Merge(new Version()), + @"Could not determine JSON object type for type System.Version. +Parameter name: content", + @"Could not determine JSON object type for type System.Version. (Parameter 'content')"); + } + + [Test] + public void MergeArraySelf() + { + var a = new JArray { "1", "2" }; + a.Merge(a, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace }); + Assert.AreEqual(new JArray { "1", "2" }, a); + } + + [Test] + public void MergeObjectSelf() + { + var a = new JObject + { + ["1"] = 1, + ["2"] = 2 + }; + a.Merge(a, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace }); + Assert.AreEqual(new JObject + { + ["1"] = 1, + ["2"] = 2 + }, a); + } + + [Test] + public void MergeArrayIntoArray_Replace() + { + var a = new JArray { "1", "2" }; + a.Merge(new string[] { "3", "4" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace }); + Assert.AreEqual(new JArray { "3", "4" }, a); + } + + [Test] + public void MergeArrayIntoArray_Concat() + { + var a = new JArray { "1", "2" }; + a.Merge(new string[] { "3", "4" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Concat }); + Assert.AreEqual(new JArray { "1", "2", "3", "4" }, a); + } + + [Test] + public void MergeArrayIntoArray_Union() + { + var a = new JArray { "1", "2" }; + a.Merge(new string[] { "2", "3", "4" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Union }); + Assert.AreEqual(new JArray { "1", "2", "3", "4" }, a); + } + + [Test] + public void MergeArrayIntoArray_Merge() + { + var a = new JArray { "1", "2" }; + a.Merge(new string[] { "2" }, new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Merge }); + Assert.AreEqual(new JArray { "2", "2" }, a); + } + [Test] public void MergeNullString() { diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj index 66e46a23e..49d267ffa 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.csproj @@ -1,8 +1,8 @@  - net46;net451;net452;net40;net35;net20;netcoreapp2.2;netcoreapp1.1;netcoreapp1.0 + net46;net40;net35;net20;net5.0;net6.0;netcoreapp3.1;netcoreapp2.1 $(TestFrameworks) - latest + 9.0 1.0 James Newton-King Newtonsoft @@ -13,9 +13,11 @@ Newtonsoft.Json.Tests false - Full + Full false + + false @@ -42,15 +44,15 @@ - - - - - - - - - + + + + + + + + + @@ -62,59 +64,13 @@ Json.NET Tests .NETFramework,Version=v4.5 - NET45;HAVE_BENCHMARKS;$(AdditionalConstants) - - - - - - - - - - - - - - - - - - - - - Json.NET Tests Portable .NET 4.0 - .NETPortable,Version=v0.0,Profile=Profile328 - PORTABLE40;$(AdditionalConstants) - - - - - - - - - - - - - - - - - - - - - Json.NET Tests Portable - .NETPortable,Version=v0.0,Profile=Profile259 - PORTABLE;$(AdditionalConstants) + NET45;HAVE_BENCHMARKS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) - - - + + + @@ -129,8 +85,8 @@ - - + + @@ -144,8 +100,8 @@ - - + + @@ -153,65 +109,86 @@ NET20;$(AdditionalConstants) - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + Json.NET Tests .NET Standard 2.0 .NETStandard,Version=v2.0 - NETSTANDARD2_0;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;$(AdditionalConstants) + NETSTANDARD2_0;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) + + + + + + + + + + + + + + + + + + + Json.NET Tests .NET 6.0 + net6.0 + NET6_0;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + Json.NET Tests .NET Standard 1.3 .NETStandard,Version=v1.3 - NETSTANDARD1_3;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;$(AdditionalConstants) + NETSTANDARD1_3;DNXCORE50;PORTABLE;HAVE_BENCHMARKS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) - - - - - - - - - - - - - + + + + + + + + + + + + + - + Json.NET Tests .NET Standard 1.0 .NETStandard,Version=v1.0 - NETSTANDARD1_0;DNXCORE50;PORTABLE;$(AdditionalConstants) + NETSTANDARD1_0;DNXCORE50;PORTABLE;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs index e98489f6e..d2c6fb656 100644 --- a/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs +++ b/Src/Newtonsoft.Json.Tests/Schema/JsonSchemaGeneratorTests.cs @@ -312,7 +312,7 @@ public void GenerateSchemaForType() Assert.IsTrue(v.IsValid(schema)); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void GenerateSchemaForISerializable() { @@ -340,7 +340,7 @@ public void GenerateSchemaForDBNull() } #endif -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER public class CustomDirectoryInfoMapper : DefaultContractResolver { public CustomDirectoryInfoMapper() @@ -376,17 +376,17 @@ public void GenerateSchemaCamelCase() generator.UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName; generator.ContractResolver = new CamelCasePropertyNamesContractResolver() { -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER IgnoreSerializableAttribute = true #endif }; - JsonSchema schema = generator.Generate(typeof(Version), true); + JsonSchema schema = generator.Generate(typeof(VersionOld), true); string json = schema.ToString(); StringAssert.AreEqual(@"{ - ""id"": ""System.Version"", + ""id"": ""Newtonsoft.Json.Tests.TestObjects.VersionOld"", ""type"": [ ""object"", ""null"" @@ -421,7 +421,7 @@ public void GenerateSchemaCamelCase() }", json); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void GenerateSchemaSerializable() { @@ -734,7 +734,7 @@ public class BulkInsertTask_DSL { } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Serializable] public sealed class SerializableTestObject { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs index a96adcb0d..7346ef077 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/CamelCasePropertyNamesContractResolverTests.cs @@ -119,7 +119,7 @@ public void JTokenWriter() string json = o.ToString(); } -#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER #pragma warning disable 618 [Test] public void MemberSearchFlags() diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs index ab680666f..7e4710e86 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ContractResolverTests.cs @@ -24,6 +24,7 @@ #endregion using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.IO; @@ -117,7 +118,7 @@ public class AddressWithDataMember [TestFixture] public class ContractResolverTests : TestFixtureBase { -#if !(PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ResolveSerializableContract() { @@ -584,7 +585,7 @@ public void SingleTypeWithMultipleContractResolvers() }", startingWithB); } -#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER #pragma warning disable 618 [Test] public void SerializeCompilerGeneratedMembers() @@ -727,6 +728,17 @@ protected virtual bool OnProp4Specified() } } + [Test] + public void NonGenericDictionary_KeyValueTypes() + { + DefaultContractResolver resolver = new DefaultContractResolver(); + + JsonDictionaryContract c = (JsonDictionaryContract)resolver.ResolveContract(typeof(IDictionary)); + + Assert.IsNull(c.DictionaryKeyType); + Assert.IsNull(c.DictionaryValueType); + } + [Test] public void DefaultContractResolverIgnoreIsSpecifiedTrue() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/DateOnlyTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/DateOnlyTests.cs new file mode 100644 index 000000000..5d84052e0 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Serialization/DateOnlyTests.cs @@ -0,0 +1,203 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if NET6_0_OR_GREATER +using System; +using System.Collections.Generic; +#if !NET20 +using System.Xml.Linq; +#endif +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +using Xunit.Abstractions; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Serialization +{ + [TestFixture] + public class DateOnlyTests : TestFixtureBase + { + [Test] + public void Serialize() + { + DateOnly d = new DateOnly(2000, 12, 29); + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"""2000-12-29""", json); + } + + [Test] + public void SerializeDefault() + { + DateOnly d = default; + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"""0001-01-01""", json); + } + + [Test] + public void SerializeMaxValue() + { + DateOnly d = DateOnly.MaxValue; + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"""9999-12-31""", json); + } + + [Test] + public void SerializeMinValue() + { + DateOnly d = DateOnly.MinValue; + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"""0001-01-01""", json); + } + + [Test] + public void SerializeNullable_Null() + { + DateOnly? d = default; + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual("null", json); + } + + [Test] + public void SerializeNullable_Value() + { + DateOnly? d = new DateOnly(2000, 12, 29); + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"""2000-12-29""", json); + } + + [Test] + public void SerializeList() + { + IList d = new List + { + new DateOnly(2000, 12, 29) + }; + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"[ + ""2000-12-29"" +]", json); + } + + [Test] + public void SerializeList_Nullable() + { + IList d = new List + { + new DateOnly(2000, 12, 29), + null + }; + string json = JsonConvert.SerializeObject(d, Formatting.Indented); + + Assert.AreEqual(@"[ + ""2000-12-29"", + null +]", json); + } + + [Test] + public void Deserialize() + { + DateOnly d = JsonConvert.DeserializeObject(@"""2000-12-29"""); + + Assert.AreEqual(new DateOnly(2000, 12, 29), d); + } + + [Test] + public void DeserializeDefault() + { + DateOnly d = JsonConvert.DeserializeObject(@"""0001-01-01"""); + + Assert.AreEqual(default(DateOnly), d); + } + + [Test] + public void DeserializeMaxValue() + { + DateOnly d = JsonConvert.DeserializeObject(@"""9999-12-31"""); + + Assert.AreEqual(DateOnly.MaxValue, d); + } + + [Test] + public void DeserializeMinValue() + { + DateOnly d = JsonConvert.DeserializeObject(@"""0001-01-01"""); + + Assert.AreEqual(DateOnly.MinValue, d); + } + + [Test] + public void DeserializeNullable_Null() + { + DateOnly? d = JsonConvert.DeserializeObject(@"null"); + + Assert.AreEqual(null, d); + } + + [Test] + public void DeserializeNullable_Value() + { + DateOnly? d = JsonConvert.DeserializeObject(@"""2000-12-29"""); + + Assert.AreEqual(new DateOnly(2000, 12, 29), d); + } + + [Test] + public void DeserializeList() + { + var l = JsonConvert.DeserializeObject>(@"[ + ""2000-12-29"" +]"); + + Assert.AreEqual(1, l.Count); + Assert.AreEqual(new DateOnly(2000, 12, 29), l[0]); + } + + [Test] + public void DeserializeList_Nullable() + { + var l = JsonConvert.DeserializeObject>(@"[ + ""2000-12-29"", + null +]"); + + Assert.AreEqual(2, l.Count); + Assert.AreEqual(new DateOnly(2000, 12, 29), l[0]); + Assert.AreEqual(null, l[1]); + } + } +} +#endif diff --git a/Src/Newtonsoft.Json.Tests/Serialization/DependencyInjectionTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/DependencyInjectionTests.cs index 959a9975a..dad1bb804 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/DependencyInjectionTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/DependencyInjectionTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || DNXCORE50 || PORTABLE || PORTABLE40) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using Autofac; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Tests.TestObjects; diff --git a/Src/Newtonsoft.Json.Tests/Serialization/DynamicTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/DynamicTests.cs index 37cfb3672..b84585403 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/DynamicTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/DynamicTests.cs @@ -101,7 +101,7 @@ public void SerializeDynamicObject() Assert.AreEqual(dynamicObject.ChildObject.Text, d.ChildObject.Text); } -#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeDynamicObjectWithObjectTracking() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/FSharpTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/FSharpTests.cs index 10192bd72..e399ecd5f 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/FSharpTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/FSharpTests.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER #if DNXCORE50 using Xunit; using Test = Xunit.FactAttribute; diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ImmutableCollectionsTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ImmutableCollectionsTests.cs index 81876c5de..09d8c4612 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ImmutableCollectionsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ImmutableCollectionsTests.cs @@ -304,6 +304,8 @@ public void DeserializeHashSetInterface() Assert.IsTrue(l.Contains("3")); Assert.IsTrue(l.Contains("II")); Assert.IsTrue(l.Contains("One")); + + Assert.IsTrue(l is ImmutableHashSet); } #endregion @@ -395,6 +397,8 @@ public void DeserializeDictionaryInterface() Assert.AreEqual("One", l[1]); Assert.AreEqual("II", l[2]); Assert.AreEqual("3", l[3]); + + Assert.IsTrue(l is ImmutableDictionary); } #endregion diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs index a7b64590c..56991bc68 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs @@ -61,7 +61,30 @@ namespace Newtonsoft.Json.Tests.Serialization [TestFixture] public class JsonSerializerCollectionsTests : TestFixtureBase { -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER + [Test] + public void DeserializeNonGenericListTypeAndReadOnlyListViaConstructor() + { + ConstructorCollectionContainer a = JsonConvert.DeserializeObject("{'a':1,'b':['aaa'],'c':['aaa']}"); + + Assert.AreEqual(1, a.A); + Assert.AreEqual(1, a.B.Count()); + Assert.AreEqual("aaa", a.B.ElementAt(0)); + Assert.AreEqual(0, a.C.Count()); + } + + public class ConstructorCollectionContainer + { + public int A { get; } + public IEnumerable B { get; } = new SortedSet(); + public IEnumerable C { get; } = new List().AsReadOnly(); + + public ConstructorCollectionContainer(int a) + { + this.A = a; + } + } + [Test] public void DeserializeConcurrentDictionaryWithNullValue() { @@ -164,7 +187,11 @@ public void FloatKey_MaxValue() { Dictionary dictionary = new Dictionary { { float.MaxValue, 1 } }; string output = JsonConvert.SerializeObject(dictionary); +#if !(NETSTANDARD2_0 || NETSTANDARD1_3 || NET6_0_OR_GREATER) Assert.AreEqual(@"{""3.40282347E+38"":1}", output); +#else + Assert.AreEqual(@"{""3.4028235E+38"":1}", output); +#endif Dictionary deserializedValue = JsonConvert.DeserializeObject>(output); Assert.AreEqual(float.MaxValue, deserializedValue.First().Key); @@ -276,7 +303,7 @@ public void CollectionJsonConstructorBadIEnumerableParameter() "Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestCollectionBadIEnumerableParameter' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Int32]'."); } -#if !(DNXCORE50 || PORTABLE) || NETSTANDARD2_0 +#if !(DNXCORE50 || PORTABLE) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class TestCollectionNonGeneric : ArrayList { [JsonConstructor] @@ -389,7 +416,7 @@ public void DictionaryJsonConstructorBadIEnumerableParameter() "Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestDictionaryBadIEnumerableParameter' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.KeyValuePair`2[System.String,System.Int32]]'."); } -#if !(DNXCORE50 || PORTABLE) || NETSTANDARD2_0 +#if !(DNXCORE50 || PORTABLE) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class TestDictionaryNonGeneric : Hashtable { [JsonConstructor] @@ -412,7 +439,7 @@ public void DictionaryJsonConstructorNonGeneric() } #endif -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class NameValueCollectionTestClass { public NameValueCollection Collection { get; set; } @@ -427,7 +454,7 @@ public void DeserializeNameValueCollection() } #endif -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class SomeObject { public string Text1 { get; set; } @@ -1069,7 +1096,7 @@ public void NullableValueGenericDictionary() Assert.AreEqual(3, v2["Third"]); } -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeConcurrentDictionary() { @@ -1783,7 +1810,7 @@ public void ComplexValuesInObjectArray() Assert.AreEqual(1, (int)((JObject)o.Data[2])["one"]); } -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeArrayAsArrayList() { @@ -2048,7 +2075,7 @@ public void ReadOnlyIntegerList() } #endif -#if !DNXCORE50 || NETSTANDARD2_0 +#if !DNXCORE50 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void EmptyStringInHashtableIsDeserialized() { @@ -2108,6 +2135,26 @@ public void DeserializeCultureInfoKey() } #endif + [Test] + public void DeserializeEmptyEnumerable_NoItems() + { + ValuesClass c = JsonConvert.DeserializeObject(@"{""Values"":[]}"); + Assert.AreEqual(0, c.Values.Count()); + } + + [Test] + public void DeserializeEmptyEnumerable_HasItems() + { + ValuesClass c = JsonConvert.DeserializeObject(@"{""Values"":[""hello""]}"); + Assert.AreEqual(1, c.Values.Count()); + Assert.AreEqual("hello", c.Values.ElementAt(0)); + } + + public class ValuesClass + { + public IEnumerable Values { get; set; } = Enumerable.Empty(); + } + [Test] public void DeserializeConstructorWithReadonlyArrayProperty() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs index 80d77bc5a..35e885258 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerTest.cs @@ -29,10 +29,10 @@ using System.Collections.Concurrent; #endif using System.Collections.Generic; -#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif -#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.ComponentModel.DataAnnotations; using System.Configuration; using System.Runtime.CompilerServices; @@ -48,6 +48,7 @@ using Xunit; using Test = Xunit.FactAttribute; using Assert = Newtonsoft.Json.Tests.XUnitAssert; +using TestCase = Xunit.InlineDataAttribute; #else using NUnit.Framework; #endif @@ -220,7 +221,7 @@ public void DeserializeGenericIEnumerableWithImplicitConversion() Assert.AreEqual("def", enumerableObject[1].Value); } -#if !(PORTABLE || PORTABLE40 || NET20 || NET35) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET20 || NET35) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void LargeIntegerAsString() { @@ -276,7 +277,7 @@ public void DeserializeBoolean_EmptyString() @"Error converting value {null} to type 'System.Boolean'. Path '[0]', line 1, position 3."); } -#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET35 || NET20) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeBooleans() { @@ -741,7 +742,7 @@ public void DeserializeNullToJTokenProperty() Assert.IsNull(otc.Value5); } -#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE40 || PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadIntegerWithError() { @@ -998,7 +999,7 @@ public void JsonSerializerProperties() serializer.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor; Assert.AreEqual(ConstructorHandling.AllowNonPublicDefaultConstructor, serializer.ConstructorHandling); -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER serializer.Context = new StreamingContext(StreamingContextStates.Other); Assert.AreEqual(new StreamingContext(StreamingContextStates.Other), serializer.Context); #endif @@ -1069,7 +1070,7 @@ public void JsonSerializerProperties() serializer.TraceWriter = traceWriter; Assert.AreEqual(traceWriter, serializer.TraceWriter); -#if !(PORTABLE || PORTABLE40 || NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER #pragma warning disable 618 serializer.TypeNameAssemblyFormat = FormatterAssemblyStyle.Full; Assert.AreEqual(FormatterAssemblyStyle.Full, serializer.TypeNameAssemblyFormat); @@ -1112,7 +1113,7 @@ public void JsonSerializerSettingsProperties() settings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor; Assert.AreEqual(ConstructorHandling.AllowNonPublicDefaultConstructor, settings.ConstructorHandling); -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER settings.Context = new StreamingContext(StreamingContextStates.Other); Assert.AreEqual(new StreamingContext(StreamingContextStates.Other), settings.Context); #endif @@ -1189,7 +1190,7 @@ public void JsonSerializerSettingsProperties() settings.TraceWriter = traceWriter; Assert.AreEqual(traceWriter, settings.TraceWriter); -#if !(PORTABLE || PORTABLE40 || NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER #pragma warning disable 618 settings.TypeNameAssemblyFormat = FormatterAssemblyStyle.Full; Assert.AreEqual(FormatterAssemblyStyle.Full, settings.TypeNameAssemblyFormat); @@ -1243,7 +1244,7 @@ public void JsonSerializerProxyProperties() serializerProxy.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor; Assert.AreEqual(ConstructorHandling.AllowNonPublicDefaultConstructor, serializerProxy.ConstructorHandling); -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER serializerProxy.Context = new StreamingContext(StreamingContextStates.Other); Assert.AreEqual(new StreamingContext(StreamingContextStates.Other), serializerProxy.Context); #endif @@ -1314,7 +1315,7 @@ public void JsonSerializerProxyProperties() serializerProxy.TraceWriter = traceWriter; Assert.AreEqual(traceWriter, serializerProxy.TraceWriter); -#if !(PORTABLE || PORTABLE40 || NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER #pragma warning disable 618 serializerProxy.TypeNameAssemblyFormat = FormatterAssemblyStyle.Full; Assert.AreEqual(FormatterAssemblyStyle.Full, serializerProxy.TypeNameAssemblyFormat); @@ -1335,7 +1336,7 @@ public void JsonSerializerProxyProperties() Assert.AreEqual(TypeNameHandling.All, serializerProxy.TypeNameHandling); } -#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeISerializableIConvertible() { @@ -1817,7 +1818,7 @@ public void TestMethodExecutorObject() Assert.AreEqual(executorObject2.clientGetResultFunction, "ClientBanSubsCB"); } -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void HashtableDeserialization() { @@ -2258,7 +2259,40 @@ public void SerializeConverableObjects() string json = JsonConvert.SerializeObject(new ConverableMembers(), Formatting.Indented); string expected = null; -#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if (NETSTANDARD2_0 || NET6_0_OR_GREATER) + expected = @"{ + ""String"": ""string"", + ""Int32"": 2147483647, + ""UInt32"": 4294967295, + ""Byte"": 255, + ""SByte"": 127, + ""Short"": 32767, + ""UShort"": 65535, + ""Long"": 9223372036854775807, + ""ULong"": 9223372036854775807, + ""Double"": 1.7976931348623157E+308, + ""Float"": 3.4028235E+38, + ""DBNull"": null, + ""Bool"": true, + ""Char"": ""\u0000"" +}"; +#elif NETSTANDARD1_3 + expected = @"{ + ""String"": ""string"", + ""Int32"": 2147483647, + ""UInt32"": 4294967295, + ""Byte"": 255, + ""SByte"": 127, + ""Short"": 32767, + ""UShort"": 65535, + ""Long"": 9223372036854775807, + ""ULong"": 9223372036854775807, + ""Double"": 1.7976931348623157E+308, + ""Float"": 3.4028235E+38, + ""Bool"": true, + ""Char"": ""\u0000"" +}"; +#elif !(PORTABLE || DNXCORE50) || NETSTANDARD1_3 expected = @"{ ""String"": ""string"", ""Int32"": 2147483647, @@ -2276,7 +2310,7 @@ public void SerializeConverableObjects() ""Char"": ""\u0000"" }"; #else - expected = @"{ + expected = @"{ ""String"": ""string"", ""Int32"": 2147483647, ""UInt32"": 4294967295, @@ -3441,7 +3475,7 @@ To fix this error either change the JSON to a JSON object (e.g. {""name"":""valu Path '', line 1, position 1."); } -#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void CannotDeserializeArrayIntoSerializable() { @@ -3482,13 +3516,9 @@ public void CannotDeserializeArrayIntoLinqToJson() { string json = @"[]"; - ExceptionAssert.Throws( + ExceptionAssert.Throws( () => { JsonConvert.DeserializeObject(json); }, - new[] - { - "Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.", - "Cannot cast from source type to destination type." // mono - }); + "Deserialized JSON type 'Newtonsoft.Json.Linq.JArray' is not compatible with expected type 'Newtonsoft.Json.Linq.JObject'. Path '', line 1, position 2."); } [Test] @@ -3559,7 +3589,7 @@ public void SerializePropertyGetError() { ContractResolver = new DefaultContractResolver { -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER IgnoreSerializableAttribute = true #endif } @@ -3576,7 +3606,7 @@ public void DeserializePropertySetError() { ContractResolver = new DefaultContractResolver { -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER IgnoreSerializableAttribute = true #endif } @@ -3593,7 +3623,7 @@ public void DeserializeEnsureTypeEmptyStringToIntError() { ContractResolver = new DefaultContractResolver { -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER IgnoreSerializableAttribute = true #endif } @@ -3610,7 +3640,7 @@ public void DeserializeEnsureTypeNullToIntError() { ContractResolver = new DefaultContractResolver { -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER IgnoreSerializableAttribute = true #endif } @@ -4072,7 +4102,7 @@ public void SerializeNonIDictionary() Assert.AreEqual("value", newModelStateDictionary["key"]); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER #if DEBUG [Test] public void SerializeISerializableInPartialTrustWithIgnoreInterface() @@ -4309,7 +4339,7 @@ public void SerializeClassWithInheritedProtectedMember() }", json); } -#if !(PORTABLE) || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeClassWithInheritedProtectedMember() { @@ -4409,7 +4439,7 @@ public void SerializeDeserializeXNodeProperties() } #endif -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeDeserializeXmlNodeProperties() { @@ -4513,7 +4543,22 @@ public void DeserializeIgnoredPropertyInConstructor() { string json = @"{""First"":""First"",""Second"":2,""Ignored"":{""Name"":""James""},""AdditionalContent"":{""LOL"":true}}"; - ConstructorCompexIgnoredProperty cc = JsonConvert.DeserializeObject(json); + var cc = JsonConvert.DeserializeObject(json); + Assert.AreEqual("First", cc.First); + Assert.AreEqual(2, cc.Second); + Assert.AreEqual(null, cc.Ignored); + } + + [Test] + public void DeserializeIgnoredPropertyInConstructorWithoutThrowingMissingMemberError() + { + string json = @"{""First"":""First"",""Second"":2,""Ignored"":{""Name"":""James""}}"; + + var cc = JsonConvert.DeserializeObject( + json, new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }); Assert.AreEqual("First", cc.First); Assert.AreEqual(2, cc.Second); Assert.AreEqual(null, cc.Ignored); @@ -4625,7 +4670,7 @@ public void DeserializeByteArray() Assert.AreEqual(0, z[1].Prop1.Length); } -#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void StringDictionaryTest() { @@ -4870,7 +4915,7 @@ public void PrivateSetterOnBaseClassProperty() Assert.AreEqual(meh.IDontWork, "meh"); } -#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeNullableStruct() { @@ -5301,7 +5346,7 @@ public void DeserializeStringIntoNullableGuid() Assert.AreEqual(new Guid("bb2f3da7-bf79-4d14-9d54-0a1f7ff5f902"), c.clientId); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeException1() { @@ -5520,7 +5565,7 @@ public void SerializeStaticReflection() Assert.AreEqual(-3, StaticTestClass.z); } -#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeDecimalsWithCulture() { @@ -5620,7 +5665,7 @@ public void DeserializeNullInt() }, "Error converting value {null} to type 'System.Int32'. Path '[3]', line 5, position 6."); } -#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeIConvertible() { @@ -5884,7 +5929,8 @@ public void DeserializeDoubleFromNullString() new[] { "Value cannot be null." + Environment.NewLine + "Parameter name: value", - "Argument cannot be null." + Environment.NewLine + "Parameter name: value" // mono + "Argument cannot be null." + Environment.NewLine + "Parameter name: value", // mono + "Value cannot be null. (Parameter 'value')" }); } @@ -5896,7 +5942,8 @@ public void DeserializeFromNullString() new[] { "Value cannot be null." + Environment.NewLine + "Parameter name: value", - "Argument cannot be null." + Environment.NewLine + "Parameter name: value" // mono + "Argument cannot be null." + Environment.NewLine + "Parameter name: value", // mono + "Value cannot be null. (Parameter 'value')" }); } @@ -6292,8 +6339,8 @@ public void DateTimeDictionaryKey_DateTime_Iso_Local() { IDictionary dic1 = new Dictionary { - { new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc), 1 }, - { new DateTime(2013, 12, 12, 12, 12, 12, DateTimeKind.Utc), 2 } + { new DateTime(2020, 12, 12, 12, 12, 12, DateTimeKind.Utc), 1 }, + { new DateTime(2023, 12, 12, 12, 12, 12, DateTimeKind.Utc), 2 } }; string json = JsonConvert.SerializeObject(dic1, Formatting.Indented, new JsonSerializerSettings @@ -6311,8 +6358,8 @@ public void DateTimeDictionaryKey_DateTime_Iso_Local() }); Assert.AreEqual(2, dic2.Count); - Assert.AreEqual(1, dic2[new DateTime(2000, 12, 12, 12, 12, 12, DateTimeKind.Utc)]); - Assert.AreEqual(2, dic2[new DateTime(2013, 12, 12, 12, 12, 12, DateTimeKind.Utc)]); + Assert.AreEqual(1, dic2[new DateTime(2020, 12, 12, 12, 12, 12, DateTimeKind.Utc)]); + Assert.AreEqual(2, dic2[new DateTime(2023, 12, 12, 12, 12, 12, DateTimeKind.Utc)]); } [Test] @@ -6348,7 +6395,7 @@ public void DeserializeEmptyJsonString() Assert.AreEqual("", s); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeAndDeserializeWithAttributes() { @@ -6718,7 +6765,7 @@ public void SerializeFloatingPointHandling() } #if !(NET20 || NET35 || NET40 || PORTABLE40) -#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeReadOnlyListWithBigInteger() { @@ -6776,7 +6823,7 @@ public void SerializeCustomTupleWithSerializableAttribute() Action doStuff = () => { obj = JsonConvert.DeserializeObject>(json); }; -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER doStuff(); Assert.AreEqual(500, obj.Item1); #else @@ -6807,7 +6854,7 @@ public void SerializeCustomTupleWithSerializableAttributeInPartialTrust() } #endif -#if !(PORTABLE || NET35 || NET20 || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || NET35 || NET20 || PORTABLE40 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeTupleWithSerializableAttribute() { @@ -7003,7 +7050,7 @@ public void NoConstructorReadOnlyDictionaryTest() } #endif -#if !(PORTABLE || NET35 || NET20 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || NET35 || NET20 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ReadTooLargeInteger() { @@ -7026,7 +7073,7 @@ public void SerializeStructWithSerializableAndDataContract() Assert.AreEqual(@"{""First"":""One"",""Second"":2}", json); -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER DefaultContractResolver r = new DefaultContractResolver(); r.IgnoreSerializableAttribute = false; @@ -7133,7 +7180,7 @@ public void DeserializeDecimal() Assert.AreEqual(1234567890.123456m, d); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DontSerializeStaticFields() { @@ -7157,7 +7204,7 @@ public void DontSerializeStaticFields() } #endif -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeBigInteger() { @@ -7298,7 +7345,7 @@ public void SerializeDictionaryWithStructKey() } #endif -#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_0 || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeDictionaryWithStructKey_Custom() { @@ -7389,7 +7436,7 @@ public void DeserializeCustomReferenceResolver_ViaProvider() Assert.AreEqual(jane, john.Spouse); } -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void TypeConverterOnInterface() { @@ -7455,7 +7502,7 @@ public void Main() ParticipantEntity deserializedProduct = JsonConvert.DeserializeObject(json); } -#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ConvertibleIdTest() { @@ -7781,7 +7828,7 @@ public void DeserializedDerivedWithPrivate() Assert.AreEqual("derived", d.DerivedProperty); } -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeNullableUnsignedLong() { @@ -7796,7 +7843,7 @@ public void DeserializeNullableUnsignedLong() } #endif -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void MailMessageConverterTest() { @@ -7945,5 +7992,226 @@ public void NullableDoubleEmptyValue() () => JsonConvert.DeserializeObject("{ A: \"\", B: 1, C: 123, D: 1.23, E: , F: null }"), "Unexpected character encountered while parsing value: ,. Path 'E', line 1, position 36."); } + + [Test] + public void SetMaxDepth_DepthExceeded() + { + JsonTextReader reader = new JsonTextReader(new StringReader("[[['text']]]")); + Assert.AreEqual(64, reader.MaxDepth); + + JsonSerializerSettings settings = new JsonSerializerSettings(); + Assert.AreEqual(64, settings.MaxDepth); + Assert.AreEqual(false, settings._maxDepthSet); + + // Default should be the same + Assert.AreEqual(reader.MaxDepth, settings.MaxDepth); + + settings.MaxDepth = 2; + Assert.AreEqual(2, settings.MaxDepth); + Assert.AreEqual(true, settings._maxDepthSet); + + JsonSerializer serializer = JsonSerializer.Create(settings); + Assert.AreEqual(2, serializer.MaxDepth); + + ExceptionAssert.Throws( + () => serializer.Deserialize(reader), + "The reader's MaxDepth of 2 has been exceeded. Path '[0][0]', line 1, position 3."); + } + + [Test] + public void SetMaxDepth_DepthNotExceeded() + { + JsonTextReader reader = new JsonTextReader(new StringReader("['text']")); + JsonSerializerSettings settings = new JsonSerializerSettings(); + + settings.MaxDepth = 2; + + JsonSerializer serializer = JsonSerializer.Create(settings); + Assert.AreEqual(2, serializer.MaxDepth); + + serializer.Deserialize(reader); + + Assert.AreEqual(64, reader.MaxDepth); + } + + [Test] + public void SetMaxDepth_DefaultDepthExceeded() + { + string json = GetNestedJson(150); + + ExceptionAssert.Throws( + () => JsonConvert.DeserializeObject(json), + "The reader's MaxDepth of 64 has been exceeded. Path '0.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63', line 65, position 135."); + } + + [Test] + public void SetMaxDepth_IncreasedDepthNotExceeded() + { + string json = GetNestedJson(150); + + JObject o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { MaxDepth = 150 }); + int depth = GetDepth(o); + + Assert.AreEqual(150, depth); + } + + [Test] + public void SetMaxDepth_NullDepthNotExceeded() + { + string json = GetNestedJson(150); + + JObject o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { MaxDepth = null }); + int depth = GetDepth(o); + + Assert.AreEqual(150, depth); + } + + [Test] + public void SetMaxDepth_MaxValueDepthNotExceeded() + { + string json = GetNestedJson(150); + + JObject o = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { MaxDepth = int.MaxValue }); + int depth = GetDepth(o); + + Assert.AreEqual(150, depth); + } + +#if DNXCORE50 + [Theory] +#endif + [TestCase(true)] + [TestCase(false)] + public void ShallowCopy_CopyAllProperties(bool specifyDateFormatString) + { + var propertyNames = typeof(JsonSerializerSettings).GetProperties().Select(property => property.Name).ToList(); + + var settings = new JsonSerializerSettings(); + if (specifyDateFormatString) + { + settings.DateFormatString = "yyyy"; + } + + var clone = new JsonSerializerSettings(settings); + + Assert.AreEqual(settings.DateFormatString, clone.DateFormatString); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.DateFormatString))); + + Assert.AreEqual(settings.DateFormatHandling, clone.DateFormatHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.DateFormatHandling))); + + Assert.AreEqual(settings.ReferenceLoopHandling, clone.ReferenceLoopHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.ReferenceLoopHandling))); + + Assert.AreEqual(settings.MissingMemberHandling, clone.MissingMemberHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.MissingMemberHandling))); + + Assert.AreEqual(settings.ObjectCreationHandling, clone.ObjectCreationHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.ObjectCreationHandling))); + + Assert.AreEqual(settings.NullValueHandling, clone.NullValueHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.NullValueHandling))); + + Assert.AreEqual(settings.DefaultValueHandling, clone.DefaultValueHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.DefaultValueHandling))); + + Assert.AreEqual(settings.Converters, clone.Converters); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.Converters))); + + Assert.AreEqual(settings.PreserveReferencesHandling, clone.PreserveReferencesHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.PreserveReferencesHandling))); + + Assert.AreEqual(settings.TypeNameHandling, clone.TypeNameHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.TypeNameHandling))); + + Assert.AreEqual(settings.MetadataPropertyHandling, clone.MetadataPropertyHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.MetadataPropertyHandling))); + +#pragma warning disable CS0618 // Type or member is obsolete + Assert.AreEqual(settings.TypeNameAssemblyFormat, clone.TypeNameAssemblyFormat); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.TypeNameAssemblyFormat))); +#pragma warning restore CS0618 // Type or member is obsolete + + Assert.AreEqual(settings.TypeNameAssemblyFormatHandling, clone.TypeNameAssemblyFormatHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.TypeNameAssemblyFormatHandling))); + + Assert.AreEqual(settings.ConstructorHandling, clone.ConstructorHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.ConstructorHandling))); + + Assert.AreEqual(settings.ContractResolver, clone.ContractResolver); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.ContractResolver))); + + Assert.AreEqual(settings.EqualityComparer, clone.EqualityComparer); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.EqualityComparer))); + +#pragma warning disable CS0618 // Type or member is obsolete + Assert.AreEqual(settings.ReferenceResolver, clone.ReferenceResolver); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.ReferenceResolver))); +#pragma warning restore CS0618 // Type or member is obsolete + + Assert.AreEqual(settings.ReferenceResolverProvider, clone.ReferenceResolverProvider); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.ReferenceResolverProvider))); + + Assert.AreEqual(settings.TraceWriter, clone.TraceWriter); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.TraceWriter))); + +#pragma warning disable CS0618 // Type or member is obsolete + Assert.AreEqual(settings.Binder, clone.Binder); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.Binder))); +#pragma warning restore CS0618 // Type or member is obsolete + + Assert.AreEqual(settings.SerializationBinder, clone.SerializationBinder); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.SerializationBinder))); + + Assert.AreEqual(settings.Error, clone.Error); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.Error))); + + Assert.AreEqual(settings.Context, clone.Context); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.Context))); + + Assert.AreEqual(settings.MaxDepth, clone.MaxDepth); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.MaxDepth))); + + Assert.AreEqual(settings.Formatting, clone.Formatting); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.Formatting))); + + Assert.AreEqual(settings.DateTimeZoneHandling, clone.DateTimeZoneHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.DateTimeZoneHandling))); + + Assert.AreEqual(settings.DateParseHandling, clone.DateParseHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.DateParseHandling))); + + Assert.AreEqual(settings.FloatFormatHandling, clone.FloatFormatHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.FloatFormatHandling))); + + Assert.AreEqual(settings.FloatParseHandling, clone.FloatParseHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.FloatParseHandling))); + + Assert.AreEqual(settings.StringEscapeHandling, clone.StringEscapeHandling); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.StringEscapeHandling))); + + Assert.AreEqual(settings.Culture, clone.Culture); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.Culture))); + + Assert.AreEqual(settings.CheckAdditionalContent, clone.CheckAdditionalContent); + Assert.IsTrue(propertyNames.Remove(nameof(JsonSerializerSettings.CheckAdditionalContent))); + + Assert.AreEqual(0, propertyNames.Count); + } + + private static int GetDepth(JToken o) + { + int depth = 1; + while (o.First != null) + { + o = o.First; + if (o.Type == JTokenType.Object) + { + depth++; + } + } + + return depth; + } } -} \ No newline at end of file +} diff --git a/Src/Newtonsoft.Json.Tests/Serialization/KebabCaseNamingStrategyTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/KebabCaseNamingStrategyTests.cs new file mode 100644 index 000000000..5737607a7 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Serialization/KebabCaseNamingStrategyTests.cs @@ -0,0 +1,324 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Serialization; +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +#else +using NUnit.Framework; +#endif +using Newtonsoft.Json.Tests.TestObjects; +using Newtonsoft.Json.Tests.TestObjects.Organization; +using Newtonsoft.Json.Linq; +using System.Reflection; +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Tests.Serialization +{ + [TestFixture] + public class KebabCaseNamingStrategyTests : TestFixtureBase + { + [Test] + public void JsonConvertSerializerSettings() + { + Person person = new Person(); + person.BirthDate = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc); + person.LastModified = new DateTime(2000, 11, 20, 23, 55, 44, DateTimeKind.Utc); + person.Name = "Name!"; + + DefaultContractResolver contractResolver = new DefaultContractResolver + { + NamingStrategy = new KebabCaseNamingStrategy() + }; + + string json = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings + { + ContractResolver = contractResolver + }); + + StringAssert.AreEqual(@"{ + ""name"": ""Name!"", + ""birth-date"": ""2000-11-20T23:55:44Z"", + ""last-modified"": ""2000-11-20T23:55:44Z"" +}", json); + + Person deserializedPerson = JsonConvert.DeserializeObject(json, new JsonSerializerSettings + { + ContractResolver = contractResolver + }); + + Assert.AreEqual(person.BirthDate, deserializedPerson.BirthDate); + Assert.AreEqual(person.LastModified, deserializedPerson.LastModified); + Assert.AreEqual(person.Name, deserializedPerson.Name); + + json = JsonConvert.SerializeObject(person, Formatting.Indented); + StringAssert.AreEqual(@"{ + ""Name"": ""Name!"", + ""BirthDate"": ""2000-11-20T23:55:44Z"", + ""LastModified"": ""2000-11-20T23:55:44Z"" +}", json); + } + + [Test] + public void JTokenWriter_OverrideSpecifiedName() + { + JsonIgnoreAttributeOnClassTestClass ignoreAttributeOnClassTestClass = new JsonIgnoreAttributeOnClassTestClass(); + ignoreAttributeOnClassTestClass.Field = int.MinValue; + + DefaultContractResolver contractResolver = new DefaultContractResolver + { + NamingStrategy = new KebabCaseNamingStrategy + { + OverrideSpecifiedNames = true + } + }; + + JsonSerializer serializer = new JsonSerializer(); + serializer.ContractResolver = contractResolver; + + JTokenWriter writer = new JTokenWriter(); + + serializer.Serialize(writer, ignoreAttributeOnClassTestClass); + + JObject o = (JObject)writer.Token; + JProperty p = o.Property("the-field"); + + Assert.IsNotNull(p); + Assert.AreEqual(int.MinValue, (int)p.Value); + } + + [Test] + public void BlogPostExample() + { + Product product = new Product + { + ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc), + Name = "Widget", + Price = 9.99m, + Sizes = new[] { "Small", "Medium", "Large" } + }; + + DefaultContractResolver contractResolver = new DefaultContractResolver + { + NamingStrategy = new KebabCaseNamingStrategy() + }; + + string json = + JsonConvert.SerializeObject( + product, + Formatting.Indented, + new JsonSerializerSettings { ContractResolver = contractResolver } + ); + + //{ + // "name": "Widget", + // "expiryDate": "\/Date(1292868060000)\/", + // "price": 9.99, + // "sizes": [ + // "Small", + // "Medium", + // "Large" + // ] + //} + + StringAssert.AreEqual(@"{ + ""name"": ""Widget"", + ""expiry-date"": ""2010-12-20T18:01:00Z"", + ""price"": 9.99, + ""sizes"": [ + ""Small"", + ""Medium"", + ""Large"" + ] +}", json); + } + +#if !(NET35 || NET20 || PORTABLE40) + [Test] + public void DynamicKebabCasePropertyNames() + { + dynamic o = new TestDynamicObject(); + o.Text = "Text!"; + o.Integer = int.MaxValue; + + DefaultContractResolver contractResolver = new DefaultContractResolver + { + NamingStrategy = new KebabCaseNamingStrategy + { + ProcessDictionaryKeys = true + } + }; + + string json = JsonConvert.SerializeObject(o, Formatting.Indented, + new JsonSerializerSettings + { + ContractResolver = contractResolver + }); + + StringAssert.AreEqual(@"{ + ""explicit"": false, + ""text"": ""Text!"", + ""integer"": 2147483647, + ""int"": 0, + ""child-object"": null +}", json); + } +#endif + + [Test] + public void DictionaryKebabCasePropertyNames_Disabled() + { + Dictionary values = new Dictionary + { + { "First", "Value1!" }, + { "Second", "Value2!" } + }; + + DefaultContractResolver contractResolver = new DefaultContractResolver + { + NamingStrategy = new KebabCaseNamingStrategy() + }; + + string json = JsonConvert.SerializeObject(values, Formatting.Indented, + new JsonSerializerSettings + { + ContractResolver = contractResolver + }); + + StringAssert.AreEqual(@"{ + ""First"": ""Value1!"", + ""Second"": ""Value2!"" +}", json); + } + + [Test] + public void DictionaryKebabCasePropertyNames_Enabled() + { + Dictionary values = new Dictionary + { + { "First", "Value1!" }, + { "Second", "Value2!" } + }; + + DefaultContractResolver contractResolver = new DefaultContractResolver + { + NamingStrategy = new KebabCaseNamingStrategy + { + ProcessDictionaryKeys = true + } + }; + + string json = JsonConvert.SerializeObject(values, Formatting.Indented, + new JsonSerializerSettings + { + ContractResolver = contractResolver + }); + + StringAssert.AreEqual(@"{ + ""first"": ""Value1!"", + ""second"": ""Value2!"" +}", json); + } + + public class PropertyAttributeNamingStrategyTestClass + { + [JsonProperty] + public string HasNoAttributeNamingStrategy { get; set; } + + [JsonProperty(NamingStrategyType = typeof(KebabCaseNamingStrategy))] + public string HasAttributeNamingStrategy { get; set; } + } + + [Test] + public void JsonPropertyAttribute_NamingStrategyType() + { + PropertyAttributeNamingStrategyTestClass c = new PropertyAttributeNamingStrategyTestClass + { + HasNoAttributeNamingStrategy = "Value1!", + HasAttributeNamingStrategy = "Value2!" + }; + + string json = JsonConvert.SerializeObject(c, Formatting.Indented); + + StringAssert.AreEqual(@"{ + ""HasNoAttributeNamingStrategy"": ""Value1!"", + ""has-attribute-naming-strategy"": ""Value2!"" +}", json); + } + + [JsonObject(NamingStrategyType = typeof(KebabCaseNamingStrategy))] + public class ContainerAttributeNamingStrategyTestClass + { + public string Prop1 { get; set; } + public string Prop2 { get; set; } + [JsonProperty(NamingStrategyType = typeof(DefaultNamingStrategy))] + public string HasAttributeNamingStrategy { get; set; } + } + + [Test] + public void JsonObjectAttribute_NamingStrategyType() + { + ContainerAttributeNamingStrategyTestClass c = new ContainerAttributeNamingStrategyTestClass + { + Prop1 = "Value1!", + Prop2 = "Value2!" + }; + + string json = JsonConvert.SerializeObject(c, Formatting.Indented); + + StringAssert.AreEqual(@"{ + ""prop1"": ""Value1!"", + ""prop2"": ""Value2!"", + ""HasAttributeNamingStrategy"": null +}", json); + } + + [JsonDictionary(NamingStrategyType = typeof(KebabCaseNamingStrategy), NamingStrategyParameters = new object[] { true, true })] + public class DictionaryAttributeNamingStrategyTestClass : Dictionary + { + } + + [Test] + public void JsonDictionaryAttribute_NamingStrategyType() + { + DictionaryAttributeNamingStrategyTestClass c = new DictionaryAttributeNamingStrategyTestClass + { + ["Key1"] = "Value1!", + ["Key2"] = "Value2!" + }; + + string json = JsonConvert.SerializeObject(c, Formatting.Indented); + + StringAssert.AreEqual(@"{ + ""key1"": ""Value1!"", + ""key2"": ""Value2!"" +}", json); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs index ea60f8a8d..e7d00dfb1 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/MetadataPropertyHandlingTests.cs @@ -324,7 +324,7 @@ public void DeserializeFromJToken() ]"; JToken t1 = JToken.Parse(json); - JToken t2 = t1.CloneToken(); + JToken t2 = t1.DeepClone(); List employees = t1.ToObject>(JsonSerializer.Create(new JsonSerializerSettings { @@ -339,7 +339,7 @@ public void DeserializeFromJToken() Assert.IsTrue(JToken.DeepEquals(t1, t2)); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeGenericObjectListWithTypeName() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/NamingStrategyEquality.cs b/Src/Newtonsoft.Json.Tests/Serialization/NamingStrategyEquality.cs index 3bb0af55d..591a2906e 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/NamingStrategyEquality.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/NamingStrategyEquality.cs @@ -97,6 +97,25 @@ public void SnakeCaseNamingStrategyEqualityVariants() CheckInequality(true, true, true); } + [Test] + public void KebabCaseStrategyEquality() + { + var s1 = new KebabCaseNamingStrategy(); + var s2 = new KebabCaseNamingStrategy(); + Assert.IsTrue(s1.Equals(s2)); + Assert.IsTrue(s1.GetHashCode() == s2.GetHashCode()); + } + + [Test] + public void KebabCaseNamingStrategyEqualityVariants() + { + CheckInequality(false, false, true); + CheckInequality(false, true, false); + CheckInequality(true, false, false); + CheckInequality(false, true, true); + CheckInequality(true, true, false); + CheckInequality(true, true, true); + } [Test] public void DifferentStrategyEquality() diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ReferenceLoopHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ReferenceLoopHandlingTests.cs index 6ac582cfe..eb35da396 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ReferenceLoopHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ReferenceLoopHandlingTests.cs @@ -151,7 +151,7 @@ public void SerializePropertyItemReferenceLoopHandling() }", json); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Serializable] public class MainClass : ISerializable { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs index 3e913ff1b..7b9bde821 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/ReflectionAttributeProviderTests.cs @@ -68,7 +68,7 @@ public ReflectionTestObject( public void GetAttributes_Property() { PropertyInfo property; -#if DNXCORE50 && !NETSTANDARD2_0 +#if DNXCORE50 && !(NETSTANDARD2_0 || NET6_0_OR_GREATER) property = Newtonsoft.Json.Utilities.TypeExtensions.GetProperty(typeof(ReflectionTestObject), "TestProperty"); #else property = typeof(ReflectionTestObject).GetProperty("TestProperty"); @@ -87,7 +87,7 @@ public void GetAttributes_Property() public void GetAttributes_Field() { FieldInfo field; -#if DNXCORE50 && !NETSTANDARD2_0 +#if DNXCORE50 && !(NETSTANDARD2_0 || NET6_0_OR_GREATER) field = (FieldInfo)Newtonsoft.Json.Utilities.TypeExtensions.GetField(typeof(ReflectionTestObject), "TestField"); #else field = typeof(ReflectionTestObject).GetField("TestField"); diff --git a/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs index b0ffd7125..727684316 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/SerializationEventAttributeTests.cs @@ -272,7 +272,7 @@ public void SerializationEventContextTestObjectSubClassTest() }", json); } -#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class SerializationEventContextTestObject { public string TestMember { get; set; } @@ -303,7 +303,7 @@ public void SerializationEventContextTest() } #endif -#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void WhenSerializationErrorDetectedBySerializer_ThenCallbackIsCalled() { diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TimeOnlyTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TimeOnlyTests.cs new file mode 100644 index 000000000..ce9c3d5f7 --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/Serialization/TimeOnlyTests.cs @@ -0,0 +1,212 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if NET6_0_OR_GREATER +using System; +using System.Collections.Generic; +#if !NET20 +using System.Xml.Linq; +#endif +#if DNXCORE50 +using Xunit; +using Test = Xunit.FactAttribute; +using Assert = Newtonsoft.Json.Tests.XUnitAssert; +using Xunit.Abstractions; +#else +using NUnit.Framework; +#endif + +namespace Newtonsoft.Json.Tests.Serialization +{ + [TestFixture] + public class TimeOnlyTests : TestFixtureBase + { + [Test] + public void Serialize() + { + TimeOnly t = new TimeOnly(23, 59, 59); + string json = JsonConvert.SerializeObject(t, Formatting.Indented); + + Assert.AreEqual(@"""23:59:59""", json); + } + + [Test] + public void Serialize_Milliseconds() + { + TimeOnly t = new TimeOnly(23, 59, 59, 999); + string json = JsonConvert.SerializeObject(t, Formatting.Indented); + + Assert.AreEqual(@"""23:59:59.999""", json); + } + + [Test] + public void SerializeDefault() + { + TimeOnly t = default; + string json = JsonConvert.SerializeObject(t, Formatting.Indented); + + Assert.AreEqual(@"""00:00:00""", json); + } + + [Test] + public void SerializeMaxValue() + { + TimeOnly t = TimeOnly.MaxValue; + string json = JsonConvert.SerializeObject(t, Formatting.Indented); + + Assert.AreEqual(@"""23:59:59.9999999""", json); + } + + [Test] + public void SerializeMinValue() + { + TimeOnly t = TimeOnly.MinValue; + string json = JsonConvert.SerializeObject(t, Formatting.Indented); + + Assert.AreEqual(@"""00:00:00""", json); + } + + [Test] + public void SerializeNullable_Null() + { + TimeOnly? t = default; + string json = JsonConvert.SerializeObject(t, Formatting.Indented); + + Assert.AreEqual("null", json); + } + + [Test] + public void SerializeNullable_Value() + { + TimeOnly? t = new TimeOnly(23, 59, 59, 999); + string json = JsonConvert.SerializeObject(t, Formatting.Indented); + + Assert.AreEqual(@"""23:59:59.999""", json); + } + + [Test] + public void SerializeList() + { + IList l = new List + { + new TimeOnly(23, 59, 59) + }; + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + + Assert.AreEqual(@"[ + ""23:59:59"" +]", json); + } + + [Test] + public void SerializeList_Nullable() + { + IList l = new List + { + new TimeOnly(23, 59, 59), + null + }; + string json = JsonConvert.SerializeObject(l, Formatting.Indented); + + Assert.AreEqual(@"[ + ""23:59:59"", + null +]", json); + } + + [Test] + public void Deserialize() + { + TimeOnly t = JsonConvert.DeserializeObject(@"""23:59:59"""); + + Assert.AreEqual(new TimeOnly(23, 59, 59), t); + } + + [Test] + public void DeserializeDefault() + { + TimeOnly t = JsonConvert.DeserializeObject(@"""00:00:00"""); + + Assert.AreEqual(default(TimeOnly), t); + } + + [Test] + public void DeserializeMaxValue() + { + TimeOnly t = JsonConvert.DeserializeObject(@"""23:59:59.9999999"""); + + Assert.AreEqual(TimeOnly.MaxValue, t); + } + + [Test] + public void DeserializeMinValue() + { + TimeOnly t = JsonConvert.DeserializeObject(@"""00:00:00"""); + + Assert.AreEqual(TimeOnly.MinValue, t); + } + + [Test] + public void DeserializeNullable_Null() + { + TimeOnly? t = JsonConvert.DeserializeObject(@"null"); + + Assert.AreEqual(null, t); + } + + [Test] + public void DeserializeNullable_Value() + { + TimeOnly? t = JsonConvert.DeserializeObject(@"""23:59:59"""); + + Assert.AreEqual(new TimeOnly(23, 59, 59), t); + } + + [Test] + public void DeserializeList() + { + var l = JsonConvert.DeserializeObject>(@"[ + ""23:59:59"" +]"); + + Assert.AreEqual(1, l.Count); + Assert.AreEqual(new TimeOnly(23, 59, 59), l[0]); + } + + [Test] + public void DeserializeList_Nullable() + { + var l = JsonConvert.DeserializeObject>(@"[ + ""23:59:59"", + null +]"); + + Assert.AreEqual(2, l.Count); + Assert.AreEqual(new TimeOnly(23, 59, 59), l[0]); + Assert.AreEqual(null, l[1]); + } + } +} +#endif diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs index eaab7dec2..86eca4375 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/TraceWriterTests.cs @@ -4,7 +4,7 @@ using System.Globalization; using System.IO; using Newtonsoft.Json.Linq; -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Numerics; #endif using System.Runtime.Serialization; @@ -121,7 +121,7 @@ public async Task DeserializedJsonWithAlreadyReadReader_Async() } #endif -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DiagnosticsTraceWriterTest() { @@ -468,7 +468,7 @@ public void Serialize() { StringArray = new[] { "1", "2" }, IntList = new List { 1, 2 }, - Version = new Version(1, 2, 3, 4), + Version = new VersionOld(1, 2, 3, 4), StringDictionary = new Dictionary { @@ -489,8 +489,8 @@ public void Serialize() Assert.AreEqual("Finished serializing System.Collections.Generic.List`1[System.Int32]. Path 'IntList'.", traceWriter.TraceRecords[2].Message); Assert.AreEqual("Started serializing System.String[]. Path 'StringArray'.", traceWriter.TraceRecords[3].Message); Assert.AreEqual("Finished serializing System.String[]. Path 'StringArray'.", traceWriter.TraceRecords[4].Message); - Assert.AreEqual("Started serializing System.Version. Path 'Version'.", traceWriter.TraceRecords[5].Message); - Assert.AreEqual("Finished serializing System.Version. Path 'Version'.", traceWriter.TraceRecords[6].Message); + Assert.AreEqual("Started serializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path 'Version'.", traceWriter.TraceRecords[5].Message); + Assert.AreEqual("Finished serializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path 'Version'.", traceWriter.TraceRecords[6].Message); Assert.AreEqual("Started serializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path 'StringDictionary'.", traceWriter.TraceRecords[7].Message); Assert.AreEqual("Finished serializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path 'StringDictionary'.", traceWriter.TraceRecords[8].Message); Assert.AreEqual("Finished serializing Newtonsoft.Json.Tests.Serialization.TraceTestObject. Path ''.", traceWriter.TraceRecords[9].Message); @@ -548,9 +548,9 @@ public void Deserialize() Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Finished deserializing System.Collections.Generic.IList`1[System.Int32]. Path 'IntList'")); Assert.AreEqual("Started deserializing System.String[]. Path 'StringArray', line 6, position 18.", traceWriter.TraceRecords[3].Message); Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing System.String[]. Path 'StringArray'")); - Assert.AreEqual("Deserializing System.Version using creator with parameters: Major, Minor, Build, Revision. Path 'Version.Major', line 11, position 12.", traceWriter.TraceRecords[5].Message); - Assert.IsTrue(traceWriter.TraceRecords[6].Message.StartsWith("Started deserializing System.Version. Path 'Version'")); - Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Finished deserializing System.Version. Path 'Version'")); + Assert.AreEqual("Deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld using creator with parameters: Major, Minor, Build, Revision. Path 'Version.Major', line 11, position 12.", traceWriter.TraceRecords[5].Message); + Assert.IsTrue(traceWriter.TraceRecords[6].Message.StartsWith("Started deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path 'Version'")); + Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path 'Version'")); Assert.AreEqual("Started deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary.1', line 19, position 8.", traceWriter.TraceRecords[8].Message); Assert.IsTrue(traceWriter.TraceRecords[9].Message.StartsWith("Finished deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary'")); Assert.IsTrue(traceWriter.TraceRecords[10].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.Serialization.TraceTestObject. Path ''")); @@ -611,9 +611,9 @@ public void Populate() Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Finished deserializing System.Collections.Generic.IList`1[System.Int32]. Path 'IntList'")); Assert.AreEqual("Started deserializing System.String[]. Path 'StringArray', line 6, position 18.", traceWriter.TraceRecords[3].Message); Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing System.String[]. Path 'StringArray'")); - Assert.AreEqual("Deserializing System.Version using creator with parameters: Major, Minor, Build, Revision. Path 'Version.Major', line 11, position 12.", traceWriter.TraceRecords[5].Message); - Assert.IsTrue(traceWriter.TraceRecords[6].Message.StartsWith("Started deserializing System.Version. Path 'Version'")); - Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Finished deserializing System.Version. Path 'Version'")); + Assert.AreEqual("Deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld using creator with parameters: Major, Minor, Build, Revision. Path 'Version.Major', line 11, position 12.", traceWriter.TraceRecords[5].Message); + Assert.IsTrue(traceWriter.TraceRecords[6].Message.StartsWith("Started deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path 'Version'")); + Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path 'Version'")); Assert.AreEqual("Started deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary.1', line 19, position 8.", traceWriter.TraceRecords[8].Message); Assert.IsTrue(traceWriter.TraceRecords[9].Message.StartsWith("Finished deserializing System.Collections.Generic.IDictionary`2[System.String,System.String]. Path 'StringDictionary'")); Assert.IsTrue(traceWriter.TraceRecords[10].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.Serialization.TraceTestObject. Path ''")); @@ -751,7 +751,7 @@ public void WriteTypeNameForObjects() IList l = new List { new Dictionary { { "key!", "value!" } }, - new Version(1, 2, 3, 4) + new VersionOld(1, 2, 3, 4) }; JsonConvert.SerializeObject(l, Formatting.Indented, new JsonSerializerSettings @@ -765,9 +765,9 @@ public void WriteTypeNameForObjects() Assert.AreEqual("Started serializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values'.", traceWriter.TraceRecords[2].Message); Assert.AreEqual("Writing type name '" + ReflectionUtils.GetTypeName(typeof(Dictionary), 0, DefaultSerializationBinder.Instance) + "' for System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0]'.", traceWriter.TraceRecords[3].Message); Assert.AreEqual("Finished serializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0]'.", traceWriter.TraceRecords[4].Message); - Assert.AreEqual("Started serializing System.Version. Path '$values[0]'.", traceWriter.TraceRecords[5].Message); - Assert.AreEqual("Writing type name '" + ReflectionUtils.GetTypeName(typeof(Version), 0, DefaultSerializationBinder.Instance) + "' for System.Version. Path '$values[1]'.", traceWriter.TraceRecords[6].Message); - Assert.AreEqual("Finished serializing System.Version. Path '$values[1]'.", traceWriter.TraceRecords[7].Message); + Assert.AreEqual("Started serializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path '$values[0]'.", traceWriter.TraceRecords[5].Message); + Assert.AreEqual("Writing type name '" + ReflectionUtils.GetTypeName(typeof(VersionOld), 0, DefaultSerializationBinder.Instance) + "' for Newtonsoft.Json.Tests.TestObjects.VersionOld. Path '$values[1]'.", traceWriter.TraceRecords[6].Message); + Assert.AreEqual("Finished serializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path '$values[1]'.", traceWriter.TraceRecords[7].Message); Assert.AreEqual("Finished serializing System.Collections.Generic.List`1[System.Object]. Path ''.", traceWriter.TraceRecords[8].Message); } @@ -837,7 +837,7 @@ public void DeserializeTypeName() ""key!"": ""value!"" }, { - ""$type"": ""System.Version, mscorlib"", + ""$type"": ""Newtonsoft.Json.Tests.TestObjects.VersionOld, Newtonsoft.Json.Tests"", ""Major"": 1, ""Minor"": 2, ""Build"": 3, @@ -860,14 +860,14 @@ public void DeserializeTypeName() Assert.AreEqual("Resolved type 'System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]], mscorlib' to System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0].$type', line 5, position 119.", traceWriter.TraceRecords[2].Message); Assert.AreEqual("Started deserializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0].key!', line 6, position 13.", traceWriter.TraceRecords[3].Message); Assert.IsTrue(traceWriter.TraceRecords[4].Message.StartsWith("Finished deserializing System.Collections.Generic.Dictionary`2[System.String,System.String]. Path '$values[0]'")); - Assert.AreEqual("Resolved type 'System.Version, mscorlib' to System.Version. Path '$values[1].$type', line 9, position 41.", traceWriter.TraceRecords[5].Message); - Assert.AreEqual("Deserializing System.Version using creator with parameters: Major, Minor, Build, Revision. Path '$values[1].Major', line 10, position 14.", traceWriter.TraceRecords[6].Message); - Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Started deserializing System.Version. Path '$values[1]'")); - Assert.IsTrue(traceWriter.TraceRecords[8].Message.StartsWith("Finished deserializing System.Version. Path '$values[1]'")); + Assert.AreEqual("Resolved type 'Newtonsoft.Json.Tests.TestObjects.VersionOld, Newtonsoft.Json.Tests' to Newtonsoft.Json.Tests.TestObjects.VersionOld. Path '$values[1].$type', line 9, position 84.", traceWriter.TraceRecords[5].Message); + Assert.AreEqual("Deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld using creator with parameters: Major, Minor, Build, Revision. Path '$values[1].Major', line 10, position 14.", traceWriter.TraceRecords[6].Message); + Assert.IsTrue(traceWriter.TraceRecords[7].Message.StartsWith("Started deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path '$values[1]'")); + Assert.IsTrue(traceWriter.TraceRecords[8].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path '$values[1]'")); Assert.IsTrue(traceWriter.TraceRecords[9].Message.StartsWith("Finished deserializing System.Collections.Generic.List`1[System.Object]. Path '$values'")); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void DeserializeISerializable() { @@ -884,11 +884,19 @@ public void DeserializeISerializable() { TraceWriter = traceWriter }); - }, "Member 'ClassName' was not found."); + }, + "Member 'ClassName' was not found.", + "Member 'Message' was not found."); Assert.IsTrue(traceWriter.TraceRecords[0].Message.StartsWith("Deserializing System.Exception using ISerializable constructor. Path ''")); Assert.AreEqual(TraceLevel.Info, traceWriter.TraceRecords[0].Level); + +#if !(NETSTANDARD2_0 || NET6_0_OR_GREATER) Assert.AreEqual("Error deserializing System.Exception. Member 'ClassName' was not found. Path '', line 1, position 2.", traceWriter.TraceRecords[1].Message); +#else + Assert.AreEqual("Error deserializing System.Exception. Member 'Message' was not found. Path '', line 1, position 2.", traceWriter.TraceRecords[1].Message); +#endif + Assert.AreEqual(TraceLevel.Error, traceWriter.TraceRecords[1].Level); } #endif @@ -931,15 +939,15 @@ public void DeserializeMissingMemberConstructor() ""MissingMemberProperty"": null }"; - JsonConvert.DeserializeObject(json, new JsonSerializerSettings + JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TraceWriter = traceWriter }); - Assert.AreEqual("Deserializing System.Version using creator with parameters: Major, Minor, Build, Revision. Path 'Major', line 2, position 10.", traceWriter.TraceRecords[0].Message); - Assert.AreEqual("Could not find member 'MissingMemberProperty' on System.Version. Path 'MissingMemberProperty', line 8, position 31.", traceWriter.TraceRecords[1].Message); - Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Started deserializing System.Version. Path ''")); - Assert.IsTrue(traceWriter.TraceRecords[3].Message.StartsWith("Finished deserializing System.Version. Path ''")); + Assert.AreEqual("Deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld using creator with parameters: Major, Minor, Build, Revision. Path 'Major', line 2, position 10.", traceWriter.TraceRecords[0].Message); + Assert.AreEqual("Could not find member 'MissingMemberProperty' on Newtonsoft.Json.Tests.TestObjects.VersionOld. Path 'MissingMemberProperty', line 8, position 31.", traceWriter.TraceRecords[1].Message); + Assert.IsTrue(traceWriter.TraceRecords[2].Message.StartsWith("Started deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path ''")); + Assert.IsTrue(traceWriter.TraceRecords[3].Message.StartsWith("Finished deserializing Newtonsoft.Json.Tests.TestObjects.VersionOld. Path ''")); } [Test] @@ -1117,7 +1125,7 @@ public async Task TraceJsonWriterTest_WriteObjectInObjectAsync() } #endif -#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET20 || NET35 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void TraceJsonWriterTest() { @@ -1402,7 +1410,7 @@ public class TraceTestObject { public IList IntList { get; set; } public string[] StringArray { get; set; } - public Version Version { get; set; } + public VersionOld Version { get; set; } public IDictionary StringDictionary { get; set; } public double Double { get; set; } } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs index b83b87b83..5ae55b99a 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/TypeNameHandlingTests.cs @@ -28,7 +28,7 @@ #else using System.Linq; #endif -#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System.Collections.ObjectModel; #if !(NET35 || NET20) using System.Dynamic; @@ -62,6 +62,125 @@ namespace Newtonsoft.Json.Tests.Serialization [TestFixture] public class TypeNameHandlingTests : TestFixtureBase { + [Test] + public void SerializeMultidimensionalByteArrayWithTypeName() + { + string array2dRef = ReflectionUtils.GetTypeName(typeof(byte[,]), TypeNameAssemblyFormatHandling.Simple, null); + string array3dRef = ReflectionUtils.GetTypeName(typeof(byte[,,]), TypeNameAssemblyFormatHandling.Simple, null); + + HasMultidimensionalByteArray o = new HasMultidimensionalByteArray + { + Array2D = new byte[,] { { 1, 2 }, { 2, 4 }, { 3, 6 } }, + Array3D = new byte[,,] { { { 1, 2, 3}, { 4, 5, 6 } } } + }; + + string json = JsonConvert.SerializeObject(o, new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.All, + Formatting = Formatting.Indented + }); + + string expectedJson = @"{ + ""$type"": ""Newtonsoft.Json.Tests.TestObjects.HasMultidimensionalByteArray, Newtonsoft.Json.Tests"", + ""Array2D"": { + ""$type"": """ + array2dRef + @""", + ""$values"": [ + [ + 1, + 2 + ], + [ + 2, + 4 + ], + [ + 3, + 6 + ] + ] + }, + ""Array3D"": { + ""$type"": """ + array3dRef + @""", + ""$values"": [ + [ + [ + 1, + 2, + 3 + ], + [ + 4, + 5, + 6 + ] + ] + ] + } +}"; + + StringAssert.AreEqual(expectedJson, json); + } + + + [Test] + public void DeserializeMultidimensionalByteArrayWithTypeName() + { + string json = @"{ + ""$type"": ""Newtonsoft.Json.Tests.TestObjects.HasMultidimensionalByteArray, Newtonsoft.Json.Tests"", + ""Array2D"": { + ""$type"": ""System.Byte[,], mscorlib"", + ""$values"": [ + [ + 1, + 2 + ], + [ + 2, + 4 + ], + [ + 3, + 6 + ] + ] + }, + ""Array3D"": { + ""$type"": ""System.Byte[,,], mscorlib"", + ""$values"": [ + [ + [ + 1, + 2, + 3 + ], + [ + 4, + 5, + 6 + ] + ] + ] + } +}"; + HasMultidimensionalByteArray value = JsonConvert.DeserializeObject(json, new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Objects + }); + + Assert.AreEqual(1, value.Array2D[0, 0]); + Assert.AreEqual(2, value.Array2D[0, 1]); + Assert.AreEqual(2, value.Array2D[1, 0]); + Assert.AreEqual(4, value.Array2D[1, 1]); + Assert.AreEqual(3, value.Array2D[2, 0]); + Assert.AreEqual(6, value.Array2D[2, 1]); + + Assert.AreEqual(1, value.Array3D[0, 0, 0]); + Assert.AreEqual(2, value.Array3D[0, 0, 1]); + Assert.AreEqual(3, value.Array3D[0, 0, 2]); + Assert.AreEqual(4, value.Array3D[0, 1, 0]); + Assert.AreEqual(5, value.Array3D[0, 1, 1]); + Assert.AreEqual(6, value.Array3D[0, 1, 2]); + } [Test] public void DeserializeByteArrayWithTypeName() @@ -1335,7 +1454,7 @@ public void ByteArrays() CollectionAssert.AreEquivalent(data, d); } -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void ISerializableTypeNameHandlingTest() { @@ -1406,19 +1525,9 @@ public void SerializationBinderWithFullName() } }); - StringAssert.AreEqual(@"{ - ""$type"": "":::MESSAGE:::, AssemblyName"", - ""Address"": ""jamesnk@testtown.com"", - ""Body"": { - ""$type"": "":::VERSION:::, AssemblyName"", - ""Major"": 1, - ""Minor"": 2, - ""Build"": 3, - ""Revision"": 4, - ""MajorRevision"": 0, - ""MinorRevision"": 4 - } -}", json); + JObject o = JObject.Parse(json); + + Assert.AreEqual(":::MESSAGE:::, AssemblyName", (string)o["$type"]); } public class MetroBinder : SerializationBinder @@ -1885,7 +1994,7 @@ public void PropertyItemTypeNameHandlingDynamic() } #endif -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeDeserialize_DictionaryContextContainsGuid_DeserializesItemAsGuid() { @@ -2314,7 +2423,7 @@ public class MyInterfaceImplementationType : IMyInterfaceType public string SomeProperty { get; set; } } -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class ParentParent { [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)] @@ -2382,7 +2491,7 @@ public class Purchase public int Quantity { get; set; } } -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class SerializableWrapper { public object Content { get; set; } diff --git a/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs b/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs index 4ab4338f2..3f6f373c7 100644 --- a/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs +++ b/Src/Newtonsoft.Json.Tests/Serialization/WebApiIntegrationTests.cs @@ -75,7 +75,7 @@ public void SerializeSerializableType() { ContractResolver = new DefaultContractResolver { -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER IgnoreSerializableAttribute = false #endif } @@ -84,7 +84,7 @@ public void SerializeSerializableType() Assert.AreEqual(expected, json); } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Test] public void SerializeInheritedType() { @@ -114,7 +114,7 @@ public InheritedType(string protectedFieldValue) : base(protectedFieldValue) } } -#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50 || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Serializable] #else [JsonObject(MemberSerialization.Fields)] diff --git a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs index 5ada7fa76..7611f2092 100644 --- a/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs +++ b/Src/Newtonsoft.Json.Tests/TestFixtureBase.cs @@ -36,6 +36,7 @@ #endif using System.Text; using System.Threading; +using Newtonsoft.Json.Linq; #if DNXCORE50 using Xunit; using Assert = Newtonsoft.Json.Tests.XUnitAssert; @@ -212,11 +213,9 @@ protected string GetDataContractJsonSerializeResult(object o) public static string ResolvePath(string path) { -#if !DNXCORE50 - return Path.Combine(TestContext.CurrentContext.TestDirectory, path); -#else - return path; -#endif + var assemblyPath = Path.GetDirectoryName(typeof(TestFixtureBase).Assembly().Location); + + return Path.Combine(assemblyPath, path); } protected string GetOffset(DateTime d, DateFormatHandling dateFormatHandling) @@ -308,6 +307,21 @@ protected string EscapeJson(string json) { return @"@""" + json.Replace(@"""", @"""""") + @""""; } + + protected string GetNestedJson(int depth) + { + JObject root = new JObject(); + JObject current = root; + for (int i = 0; i < depth - 1; i++) + { + JObject nested = new JObject(); + current[i.ToString()] = nested; + + current = nested; + } + + return root.ToString(); + } } public static class CustomAssert @@ -375,7 +389,7 @@ public static TException Throws(Action action, params string[] possi { action(); - Assert.Fail("Exception of type {0} expected. No exception thrown.", typeof(TException).Name); + Assert.Fail("Exception of type " + typeof(TException).Name + " expected. No exception thrown."); return null; } catch (TException ex) @@ -408,7 +422,7 @@ public static async Task ThrowsAsync(Func action, { await action(); - Assert.Fail("Exception of type {0} expected. No exception thrown.", typeof(TException).Name); + Assert.Fail("Exception of type " + typeof(TException).Name + " expected. No exception thrown."); return null; } catch (TException ex) diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/AnswerFilterModel.cs b/Src/Newtonsoft.Json.Tests/TestObjects/AnswerFilterModel.cs index 501e00db9..e7b81c6f2 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/AnswerFilterModel.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/AnswerFilterModel.cs @@ -34,7 +34,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Serializable] public class AnswerFilterModel { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/AttachmentReadConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/AttachmentReadConverter.cs index 0f2f2ca73..ce86092ce 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/AttachmentReadConverter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/AttachmentReadConverter.cs @@ -28,7 +28,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class AttachmentReadConverter : JsonConverter { public override bool CanConvert(Type objectType) diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConsoleWriter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConsoleWriter.cs index d128c0e5e..d6e005249 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ConsoleWriter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConsoleWriter.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [TypeConverter(typeof(MyInterfaceConverter))] internal class ConsoleWriter : IMyInterface { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs index 73c194ae6..bdb835408 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConverableMembers.cs @@ -41,7 +41,7 @@ public class ConverableMembers public ulong ULong = long.MaxValue; public double Double = double.MaxValue; public float Float = float.MaxValue; -#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public DBNull DBNull = DBNull.Value; #endif public bool Bool = true; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConvertableIntTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConvertableIntTestClass.cs index 9bc040c3b..276ad53b3 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ConvertableIntTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConvertableIntTestClass.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER public class ConvertableIntTestClass { public ConvertibleInt Integer { get; set; } diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ConvertibleInt.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ConvertibleInt.cs index 0762d31be..edbf2d784 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ConvertibleInt.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ConvertibleInt.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER public struct ConvertibleInt : IConvertible { private readonly int _value; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/CustomerDataSet.cs b/Src/Newtonsoft.Json.Tests/TestObjects/CustomerDataSet.cs index 05873fafd..e17cdf9fe 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/CustomerDataSet.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/CustomerDataSet.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(PORTABLE40 || PORTABLE || DNXCORE50) || NETSTANDARD2_0 +#if !(PORTABLE40 || PORTABLE || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Collections.Generic; using System.Text; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/EncodingReadConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/EncodingReadConverter.cs index 98005e347..78d2d1417 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/EncodingReadConverter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/EncodingReadConverter.cs @@ -28,7 +28,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class EncodingReadConverter : JsonConverter { public override bool CanConvert(Type objectType) diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Shape.cs b/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Shape.cs index 9f6a71b23..c1d38c1bd 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Shape.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Shape.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Diagnostics; using System.Runtime.CompilerServices; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Tags.cs b/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Tags.cs index 8ab1aef9c..021cc9aa0 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Tags.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/GeometricForms/Tags.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER namespace Newtonsoft.Json.Tests.TestObjects.GeometricForms { public static class Tags diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/HasByteArray.cs b/Src/Newtonsoft.Json.Tests/TestObjects/HasByteArray.cs index d9fd7d386..102bf70b4 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/HasByteArray.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/HasByteArray.cs @@ -29,4 +29,10 @@ internal class HasByteArray { public byte[] EncryptedPassword { get; set; } } + + internal class HasMultidimensionalByteArray + { + public byte[,] Array2D { get; set; } + public byte[,,] Array3D { get; set; } + } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/IMyInterface.cs b/Src/Newtonsoft.Json.Tests/TestObjects/IMyInterface.cs index aeda3e84a..786080f1f 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/IMyInterface.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/IMyInterface.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [TypeConverter(typeof(MyInterfaceConverter))] internal interface IMyInterface { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs index d8329902a..05c03a9f8 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/ListOfIds.cs @@ -66,7 +66,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override bool CanConvert(Type objectType) { -#if DNXCORE50 && !NETSTANDARD2_0 +#if DNXCORE50 && !(NETSTANDARD2_0 || NET6_0_OR_GREATER) return Newtonsoft.Json.Utilities.TypeExtensions.IsAssignableFrom(typeof(IList), objectType); #else return typeof(IList).IsAssignableFrom(objectType); diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/MailAddressReadConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/MailAddressReadConverter.cs index 65dbf1219..206cea47c 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/MailAddressReadConverter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/MailAddressReadConverter.cs @@ -28,7 +28,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class MailAddressReadConverter : JsonConverter { public override bool CanConvert(Type objectType) diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Money/Currency.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Money/Currency.cs index 311efc921..5f026b49b 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/Money/Currency.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Money/Currency.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET40 || NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER using System; using System.Diagnostics; using System.Runtime.CompilerServices; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Money/Tags.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Money/Tags.cs index 20533c17e..dc4ce8342 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/Money/Tags.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Money/Tags.cs @@ -23,7 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion -#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER namespace Newtonsoft.Json.Tests.TestObjects.Money { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/MyInterfaceConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/MyInterfaceConverter.cs index f33a7788e..2a71266e4 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/MyInterfaceConverter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/MyInterfaceConverter.cs @@ -35,7 +35,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER internal class MyInterfaceConverter : TypeConverter { private readonly List _writers = new List diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/NullableStructPropertyClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/NullableStructPropertyClass.cs index cf4e45e61..032f8d2fb 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/NullableStructPropertyClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/NullableStructPropertyClass.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [DataContract] public class NullableStructPropertyClass { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PersonSerializable.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PersonSerializable.cs index 9f8985f4e..2d4c0f33d 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PersonSerializable.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PersonSerializable.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Serializable] public class PersonSerializable { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/PreserveReferencesCallbackTestObject.cs b/Src/Newtonsoft.Json.Tests/TestObjects/PreserveReferencesCallbackTestObject.cs index c25c9adfd..838509c08 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/PreserveReferencesCallbackTestObject.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/PreserveReferencesCallbackTestObject.cs @@ -28,7 +28,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Serializable] public class PreserveReferencesCallbackTestObject : ISerializable { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/Ratio.cs b/Src/Newtonsoft.Json.Tests/TestObjects/Ratio.cs index 87e1d01b9..3ae7136ad 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/Ratio.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/Ratio.cs @@ -29,7 +29,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER [Serializable] public struct Ratio : IConvertible, IFormattable, ISerializable { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/SerializableContractResolver.cs b/Src/Newtonsoft.Json.Tests/TestObjects/SerializableContractResolver.cs index 68bdacc00..5c0539336 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/SerializableContractResolver.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/SerializableContractResolver.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(PORTABLE || NET35 || NET20 || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(PORTABLE || NET35 || NET20 || PORTABLE40 || DNXCORE50) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER public class SerializableContractResolver : DefaultContractResolver { public SerializableContractResolver() diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/StringDictionaryTestClass.cs b/Src/Newtonsoft.Json.Tests/TestObjects/StringDictionaryTestClass.cs index 31e803bb8..682a2ab50 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/StringDictionaryTestClass.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/StringDictionaryTestClass.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class StringDictionaryTestClass { public StringDictionary StringDictionaryProperty { get; set; } diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/StructISerializable.cs b/Src/Newtonsoft.Json.Tests/TestObjects/StructISerializable.cs index 7d2d2a66a..f20092721 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/StructISerializable.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/StructISerializable.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 +#if !(NET20 || DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER [DataContract] public struct StructISerializable : ISerializable { diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/TraceWriter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/TraceWriter.cs index bfaf00fc4..1add12e86 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/TraceWriter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/TraceWriter.cs @@ -25,7 +25,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER internal class TraceWriter : IMyInterface { public string Name diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/TypeConverterJsonConverter.cs b/Src/Newtonsoft.Json.Tests/TestObjects/TypeConverterJsonConverter.cs index 9a8d65159..5ad4907f9 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/TypeConverterJsonConverter.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/TypeConverterJsonConverter.cs @@ -34,7 +34,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 +#if !(NET35 || NET20 || PORTABLE || PORTABLE40) || NETSTANDARD1_3 || NETSTANDARD2_0 || NET6_0_OR_GREATER internal class TypeConverterJsonConverter : JsonConverter { private TypeConverter GetConverter(Type type) diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs b/Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs index 35581a304..d88b75ae3 100644 --- a/Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs +++ b/Src/Newtonsoft.Json.Tests/TestObjects/TypedSubHashtable.cs @@ -27,7 +27,7 @@ namespace Newtonsoft.Json.Tests.TestObjects { -#if !(DNXCORE50) || NETSTANDARD2_0 +#if !(DNXCORE50) || NETSTANDARD2_0 || NET6_0_OR_GREATER public class TypedSubHashtable { public string Name; diff --git a/Src/Newtonsoft.Json.Tests/TestObjects/VersionOld.cs b/Src/Newtonsoft.Json.Tests/TestObjects/VersionOld.cs new file mode 100644 index 000000000..67216e4aa --- /dev/null +++ b/Src/Newtonsoft.Json.Tests/TestObjects/VersionOld.cs @@ -0,0 +1,117 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Tests.TestObjects +{ + [Serializable] + public sealed class VersionOld : IComparable, IComparable, IEquatable + { + // AssemblyName depends on the order staying the same + private readonly int _Major; // Do not rename (binary serialization) + private readonly int _Minor; // Do not rename (binary serialization) + private readonly int _Build = -1; // Do not rename (binary serialization) + private readonly int _Revision = -1; // Do not rename (binary serialization) + + [JsonConstructor] + public VersionOld(int major, int minor, int build, int revision) + { + _Major = major; + _Minor = minor; + _Build = build; + _Revision = revision; + } + + public VersionOld(int major, int minor, int build) + { + _Major = major; + _Minor = minor; + _Build = build; + } + + public VersionOld(int major, int minor) + { + _Major = major; + _Minor = minor; + } + + public VersionOld() + { + _Major = 0; + _Minor = 0; + } + + // Properties for setting and getting version numbers + public int Major => _Major; + + public int Minor => _Minor; + + public int Build => _Build; + + public int Revision => _Revision; + + public short MajorRevision => (short)(_Revision >> 16); + + public short MinorRevision => (short)(_Revision & 0xFFFF); + + public int CompareTo(object version) + { + if (version == null) + { + return 1; + } + + if (version is VersionOld v) + { + return CompareTo(v); + } + + throw new ArgumentException(); + } + + public int CompareTo(VersionOld value) + { + return + object.ReferenceEquals(value, this) ? 0 : + value is null ? 1 : + _Major != value._Major ? (_Major > value._Major ? 1 : -1) : + _Minor != value._Minor ? (_Minor > value._Minor ? 1 : -1) : + _Build != value._Build ? (_Build > value._Build ? 1 : -1) : + _Revision != value._Revision ? (_Revision > value._Revision ? 1 : -1) : + 0; + } + + public bool Equals(VersionOld obj) + { + return object.ReferenceEquals(obj, this) || + (!(obj is null) && + _Major == obj._Major && + _Minor == obj._Minor && + _Build == obj._Build && + _Revision == obj._Revision); + } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs index ef6e561d9..9488ab9ee 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/ExpressionReflectionDelegateFactoryTests.cs @@ -145,7 +145,8 @@ public void DefaultConstructor_Abstract() }, new[] { "Cannot create an abstract class.", - "Cannot create an abstract class 'System.Type'." // mono + "Cannot create an abstract class 'System.Type'.", // mono + "Cannot dynamically create an instance of type 'System.Type'. Reason: Cannot create an abstract class." // net60 }); } diff --git a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs index 85ff18655..4d8965ace 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs @@ -98,5 +98,34 @@ public void ToSnakeCaseTest() Assert.AreEqual("9999-12-31_t23:59:59.9999999_z", StringUtils.ToSnakeCase("9999-12-31T23:59:59.9999999Z")); Assert.AreEqual("hi!!_this_is_text._time_to_test.", StringUtils.ToSnakeCase("Hi!! This is text. Time to test.")); } + + [Test] + public void ToKebabCaseTest() + { + Assert.AreEqual("url-value", StringUtils.ToKebabCase("URLValue")); + Assert.AreEqual("url", StringUtils.ToKebabCase("URL")); + Assert.AreEqual("id", StringUtils.ToKebabCase("ID")); + Assert.AreEqual("i", StringUtils.ToKebabCase("I")); + Assert.AreEqual("", StringUtils.ToKebabCase("")); + Assert.AreEqual(null, StringUtils.ToKebabCase(null)); + Assert.AreEqual("person", StringUtils.ToKebabCase("Person")); + Assert.AreEqual("i-phone", StringUtils.ToKebabCase("iPhone")); + Assert.AreEqual("i-phone", StringUtils.ToKebabCase("IPhone")); + Assert.AreEqual("i-phone", StringUtils.ToKebabCase("I Phone")); + Assert.AreEqual("i-phone", StringUtils.ToKebabCase("I Phone")); + Assert.AreEqual("i-phone", StringUtils.ToKebabCase(" IPhone")); + Assert.AreEqual("i-phone", StringUtils.ToKebabCase(" IPhone ")); + Assert.AreEqual("is-cia", StringUtils.ToKebabCase("IsCIA")); + Assert.AreEqual("vm-q", StringUtils.ToKebabCase("VmQ")); + Assert.AreEqual("xml2-json", StringUtils.ToKebabCase("Xml2Json")); + Assert.AreEqual("ke-ba-bc-as-e", StringUtils.ToKebabCase("KeBaBcAsE")); + Assert.AreEqual("ke-b--a-bc-as-e", StringUtils.ToKebabCase("KeB--aBcAsE")); + Assert.AreEqual("ke-b--a-bc-as-e", StringUtils.ToKebabCase("KeB-- aBcAsE")); + Assert.AreEqual("already-kebab-case-", StringUtils.ToKebabCase("already-kebab-case- ")); + Assert.AreEqual("is-json-property", StringUtils.ToKebabCase("IsJSONProperty")); + Assert.AreEqual("shouting-case", StringUtils.ToKebabCase("SHOUTING-CASE")); + Assert.AreEqual("9999-12-31-t23:59:59.9999999-z", StringUtils.ToKebabCase("9999-12-31T23:59:59.9999999Z")); + Assert.AreEqual("hi!!-this-is-text.-time-to-test.", StringUtils.ToKebabCase("Hi!! This is text. Time to test.")); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.sln b/Src/Newtonsoft.Json.sln index cbfa2bb4a..10feeda9c 100644 --- a/Src/Newtonsoft.Json.sln +++ b/Src/Newtonsoft.Json.sln @@ -1,10 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29123.89 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B520C700-7D45-4D82-BFB5-218FA68CF5CF}" ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props global.json = global.json NuGet.Config = NuGet.Config EndProjectSection @@ -13,7 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Newtonsoft.Json", "Newtonso EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Newtonsoft.Json.Tests", "Newtonsoft.Json.Tests\Newtonsoft.Json.Tests.csproj", "{462EA9B9-8532-4330-9160-DF3450C70880}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newtonsoft.Json.TestConsole", "Newtonsoft.Json.TestConsole\Newtonsoft.Json.TestConsole.csproj", "{3CC9C2DF-CD0A-4096-BF46-B4AFDF0147D2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Newtonsoft.Json.TestConsole", "Newtonsoft.Json.TestConsole\Newtonsoft.Json.TestConsole.csproj", "{3CC9C2DF-CD0A-4096-BF46-B4AFDF0147D2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -65,4 +66,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {225F391C-701E-49A2-8193-085EC2586689} + EndGlobalSection EndGlobal diff --git a/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs b/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs index 638039faf..3ac0020c4 100644 --- a/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs +++ b/Src/Newtonsoft.Json/Bson/BsonBinaryType.cs @@ -25,6 +25,8 @@ using System; +#nullable disable + namespace Newtonsoft.Json.Bson { internal enum BsonBinaryType : byte diff --git a/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs index 815bbe11a..1f3c0aa3c 100644 --- a/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs +++ b/Src/Newtonsoft.Json/Bson/BsonBinaryWriter.cs @@ -29,6 +29,8 @@ using System.Text; using Newtonsoft.Json.Utilities; +#nullable disable + namespace Newtonsoft.Json.Bson { internal class BsonBinaryWriter diff --git a/Src/Newtonsoft.Json/Bson/BsonObjectId.cs b/Src/Newtonsoft.Json/Bson/BsonObjectId.cs index 4c57e7f90..4e1461d19 100644 --- a/Src/Newtonsoft.Json/Bson/BsonObjectId.cs +++ b/Src/Newtonsoft.Json/Bson/BsonObjectId.cs @@ -26,6 +26,8 @@ using System; using Newtonsoft.Json.Utilities; +#nullable disable + namespace Newtonsoft.Json.Bson { /// diff --git a/Src/Newtonsoft.Json/Bson/BsonReader.cs b/Src/Newtonsoft.Json/Bson/BsonReader.cs index fe8a24811..45569331d 100644 --- a/Src/Newtonsoft.Json/Bson/BsonReader.cs +++ b/Src/Newtonsoft.Json/Bson/BsonReader.cs @@ -32,6 +32,8 @@ using Newtonsoft.Json.Utilities; using Newtonsoft.Json.Linq; +#nullable disable + namespace Newtonsoft.Json.Bson { /// diff --git a/Src/Newtonsoft.Json/Bson/BsonToken.cs b/Src/Newtonsoft.Json/Bson/BsonToken.cs index 631584c96..202bca6e5 100644 --- a/Src/Newtonsoft.Json/Bson/BsonToken.cs +++ b/Src/Newtonsoft.Json/Bson/BsonToken.cs @@ -26,6 +26,8 @@ using System.Collections; using System.Collections.Generic; +#nullable disable + namespace Newtonsoft.Json.Bson { internal abstract class BsonToken diff --git a/Src/Newtonsoft.Json/Bson/BsonType.cs b/Src/Newtonsoft.Json/Bson/BsonType.cs index e1192985c..fefae2c9b 100644 --- a/Src/Newtonsoft.Json/Bson/BsonType.cs +++ b/Src/Newtonsoft.Json/Bson/BsonType.cs @@ -23,6 +23,8 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion +#nullable disable + namespace Newtonsoft.Json.Bson { internal enum BsonType : sbyte diff --git a/Src/Newtonsoft.Json/Bson/BsonWriter.cs b/Src/Newtonsoft.Json/Bson/BsonWriter.cs index 3d1c0a15a..47d34fa3b 100644 --- a/Src/Newtonsoft.Json/Bson/BsonWriter.cs +++ b/Src/Newtonsoft.Json/Bson/BsonWriter.cs @@ -35,6 +35,8 @@ using Newtonsoft.Json.Linq; using System.Globalization; +#nullable disable + namespace Newtonsoft.Json.Bson { /// diff --git a/Src/Newtonsoft.Json/CompatibilitySuppressions.xml b/Src/Newtonsoft.Json/CompatibilitySuppressions.xml new file mode 100644 index 000000000..64d04acc5 --- /dev/null +++ b/Src/Newtonsoft.Json/CompatibilitySuppressions.xml @@ -0,0 +1,104 @@ + + + + + CP0001 + T:Newtonsoft.Json.Serialization.Func`1 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Func`2 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Func`3 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Func`4 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Func`5 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Action + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Action`2 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Action`3 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.Serialization.Action`4 + lib/net20/Newtonsoft.Json.dll + lib/net35/Newtonsoft.Json.dll + + + + CP0001 + T:System.Runtime.Serialization.Formatters.FormatterAssemblyStyle + lib/netstandard1.3/Newtonsoft.Json.dll + lib/netstandard2.0/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.SerializationBinder + lib/netstandard1.3/Newtonsoft.Json.dll + lib/netstandard2.0/Newtonsoft.Json.dll + + + CP0001 + T:Newtonsoft.Json.TraceLevel + lib/netstandard1.3/Newtonsoft.Json.dll + lib/netstandard2.0/Newtonsoft.Json.dll + + + + CP0007 + T:Newtonsoft.Json.Serialization.DefaultSerializationBinder + lib/netstandard1.3/Newtonsoft.Json.dll + lib/netstandard2.0/Newtonsoft.Json.dll + + + + CP0002 + M:Newtonsoft.Json.Serialization.ITraceWriter.Trace(Newtonsoft.Json.TraceLevel,System.String,System.Exception) + lib/netstandard1.3/Newtonsoft.Json.dll + lib/netstandard2.0/Newtonsoft.Json.dll + + + CP0002 + M:Newtonsoft.Json.Serialization.MemoryTraceWriter.Trace(Newtonsoft.Json.TraceLevel,System.String,System.Exception) + lib/netstandard1.3/Newtonsoft.Json.dll + lib/netstandard2.0/Newtonsoft.Json.dll + + + + CP0006 + M:Newtonsoft.Json.Serialization.ITraceWriter.Trace(System.Diagnostics.TraceLevel,System.String,System.Exception) + lib/netstandard1.3/Newtonsoft.Json.dll + lib/netstandard2.0/Newtonsoft.Json.dll + + \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs b/Src/Newtonsoft.Json/Converters/BinaryConverter.cs index 83f0717b8..47833a2ac 100644 --- a/Src/Newtonsoft.Json/Converters/BinaryConverter.cs +++ b/Src/Newtonsoft.Json/Converters/BinaryConverter.cs @@ -28,6 +28,7 @@ using System.Globalization; using Newtonsoft.Json.Utilities; using System.Collections.Generic; +using System.Diagnostics; #if HAVE_ADO_NET using System.Data.SqlTypes; #endif @@ -42,7 +43,7 @@ public class BinaryConverter : JsonConverter #if HAVE_LINQ private const string BinaryTypeName = "System.Data.Linq.Binary"; private const string BinaryToArrayName = "ToArray"; - private static ReflectionObject _reflectionObject; + private static ReflectionObject? _reflectionObject; #endif /// @@ -51,7 +52,7 @@ public class BinaryConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -70,7 +71,9 @@ private byte[] GetByteArray(object value) if (value.GetType().FullName == BinaryTypeName) { EnsureReflectionObject(value.GetType()); - return (byte[])_reflectionObject.GetValue(value, BinaryToArrayName); + MiscellaneousUtils.Assert(_reflectionObject != null); + + return (byte[])_reflectionObject.GetValue(value, BinaryToArrayName)!; } #endif #if HAVE_ADO_NET @@ -101,7 +104,7 @@ private static void EnsureReflectionObject(Type t) /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -123,7 +126,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { // current token is already at base64 string // unable to call ReadAsBytes so do it the old fashion way - string encodedData = reader.Value.ToString(); + string encodedData = reader.Value!.ToString()!; data = Convert.FromBase64String(encodedData); } else @@ -132,15 +135,16 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; #if HAVE_LINQ if (t.FullName == BinaryTypeName) { EnsureReflectionObject(t); + MiscellaneousUtils.Assert(_reflectionObject != null); - return _reflectionObject.Creator(data); + return _reflectionObject.Creator!(data); } #endif diff --git a/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs b/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs index 5571c37f1..5f918de25 100644 --- a/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs +++ b/Src/Newtonsoft.Json/Converters/BsonObjectIdConverter.cs @@ -28,6 +28,8 @@ using System.Globalization; using Newtonsoft.Json.Utilities; +#nullable disable + namespace Newtonsoft.Json.Converters { /// diff --git a/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs b/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs index 8f54c0c62..f693ce574 100644 --- a/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs +++ b/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs @@ -41,7 +41,7 @@ public abstract class CustomCreationConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotSupportedException("CustomCreationConverter should only be used while deserializing."); } @@ -54,7 +54,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { diff --git a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs index 7605f9c4e..214728e67 100644 --- a/Src/Newtonsoft.Json/Converters/DataSetConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataSetConverter.cs @@ -41,7 +41,7 @@ public class DataSetConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -50,7 +50,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } DataSet dataSet = (DataSet)value; - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; DataTableConverter converter = new DataTableConverter(); @@ -74,7 +74,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -84,7 +84,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist // handle typed datasets DataSet ds = (objectType == typeof(DataSet)) ? new DataSet() - : (DataSet)Activator.CreateInstance(objectType); + : (DataSet)Activator.CreateInstance(objectType)!; DataTableConverter converter = new DataTableConverter(); @@ -92,10 +92,10 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist while (reader.TokenType == JsonToken.PropertyName) { - DataTable dt = ds.Tables[(string)reader.Value]; + DataTable? dt = ds.Tables[(string)reader.Value!]; bool exists = (dt != null); - dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer); + dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer)!; if (!exists) { diff --git a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs index 5a7f6886b..1a32e5121 100644 --- a/Src/Newtonsoft.Json/Converters/DataTableConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DataTableConverter.cs @@ -45,7 +45,7 @@ public class DataTableConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -54,7 +54,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } DataTable table = (DataTable)value; - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; writer.WriteStartArray(); @@ -87,7 +87,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -99,14 +99,14 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist // handle typed datasets dt = (objectType == typeof(DataTable)) ? new DataTable() - : (DataTable)Activator.CreateInstance(objectType); + : (DataTable)Activator.CreateInstance(objectType)!; } // DataTable is inside a DataSet // populate the name from the property name if (reader.TokenType == JsonToken.PropertyName) { - dt.TableName = (string)reader.Value; + dt.TableName = (string)reader.Value!; reader.ReadAndAssert(); @@ -140,11 +140,11 @@ private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer se while (reader.TokenType == JsonToken.PropertyName) { - string columnName = (string)reader.Value; + string columnName = (string)reader.Value!; reader.ReadAndAssert(); - DataColumn column = dt.Columns[columnName]; + DataColumn? column = dt.Columns[columnName]; if (column == null) { Type columnType = GetColumnDataType(reader); @@ -177,7 +177,7 @@ private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer se reader.ReadAndAssert(); } - List o = new List(); + List o = new List(); while (reader.TokenType != JsonToken.EndArray) { @@ -185,7 +185,7 @@ private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer se reader.ReadAndAssert(); } - Array destinationArray = Array.CreateInstance(column.DataType.GetElementType(), o.Count); + Array destinationArray = Array.CreateInstance(column.DataType.GetElementType()!, o.Count); ((IList)o).CopyTo(destinationArray, 0); dr[columnName] = destinationArray; @@ -218,7 +218,7 @@ private static Type GetColumnDataType(JsonReader reader) case JsonToken.String: case JsonToken.Date: case JsonToken.Bytes: - return reader.ValueType; + return reader.ValueType!; case JsonToken.Null: case JsonToken.Undefined: case JsonToken.EndArray: diff --git a/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs b/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs index d850db9c7..c4c5d08a0 100644 --- a/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs +++ b/Src/Newtonsoft.Json/Converters/DiscriminatedUnionConverter.cs @@ -48,17 +48,32 @@ public class DiscriminatedUnionConverter : JsonConverter #region UnionDefinition internal class Union { - public List Cases; - public FSharpFunction TagReader { get; set; } + public readonly FSharpFunction TagReader; + public readonly List Cases; + + public Union(FSharpFunction tagReader, List cases) + { + TagReader = tagReader; + Cases = cases; + } } internal class UnionCase { - public int Tag; - public string Name; - public PropertyInfo[] Fields; - public FSharpFunction FieldReader; - public FSharpFunction Constructor; + public readonly int Tag; + public readonly string Name; + public readonly PropertyInfo[] Fields; + public readonly FSharpFunction FieldReader; + public readonly FSharpFunction Constructor; + + public UnionCase(int tag, string name, PropertyInfo[] fields, FSharpFunction fieldReader, FSharpFunction constructor) + { + Tag = tag; + Name = name; + Fields = fields; + FieldReader = fieldReader; + Constructor = constructor; + } } #endregion @@ -74,31 +89,28 @@ private static Type CreateUnionTypeLookup(Type t) // need to get declaring type to avoid duplicate Unions in cache // hacky but I can't find an API to get the declaring type without GetUnionCases - object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null); + object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!; object caseInfo = cases.First(); - Type unionType = (Type)FSharpUtils.GetUnionCaseInfoDeclaringType(caseInfo); + Type unionType = (Type)FSharpUtils.Instance.GetUnionCaseInfoDeclaringType(caseInfo)!; return unionType; } private static Union CreateUnion(Type t) { - Union u = new Union(); - - u.TagReader = (FSharpFunction)FSharpUtils.PreComputeUnionTagReader(null, t, null); - u.Cases = new List(); + Union u = new Union((FSharpFunction)FSharpUtils.Instance.PreComputeUnionTagReader(null, t, null), new List()); - object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null); + object[] cases = (object[])FSharpUtils.Instance.GetUnionCases(null, t, null)!; foreach (object unionCaseInfo in cases) { - UnionCase unionCase = new UnionCase(); - unionCase.Tag = (int)FSharpUtils.GetUnionCaseInfoTag(unionCaseInfo); - unionCase.Name = (string)FSharpUtils.GetUnionCaseInfoName(unionCaseInfo); - unionCase.Fields = (PropertyInfo[])FSharpUtils.GetUnionCaseInfoFields(unionCaseInfo); - unionCase.FieldReader = (FSharpFunction)FSharpUtils.PreComputeUnionReader(null, unionCaseInfo, null); - unionCase.Constructor = (FSharpFunction)FSharpUtils.PreComputeUnionConstructor(null, unionCaseInfo, null); + UnionCase unionCase = new UnionCase( + (int)FSharpUtils.Instance.GetUnionCaseInfoTag(unionCaseInfo), + (string)FSharpUtils.Instance.GetUnionCaseInfoName(unionCaseInfo), + (PropertyInfo[])FSharpUtils.Instance.GetUnionCaseInfoFields(unionCaseInfo)!, + (FSharpFunction)FSharpUtils.Instance.PreComputeUnionReader(null, unionCaseInfo, null), + (FSharpFunction)FSharpUtils.Instance.PreComputeUnionConstructor(null, unionCaseInfo, null)); u.Cases.Add(unionCase); } @@ -112,9 +124,15 @@ private static Union CreateUnion(Type t) /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + if (value == null) + { + writer.WriteNull(); + return; + } + + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; Type unionType = UnionTypeLookupCache.Get(value.GetType()); Union union = UnionCache.Get(unionType); @@ -127,7 +145,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s writer.WriteValue(caseInfo.Name); if (caseInfo.Fields != null && caseInfo.Fields.Length > 0) { - object[] fields = (object[])caseInfo.FieldReader.Invoke(value); + object[] fields = (object[])caseInfo.FieldReader.Invoke(value)!; writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(FieldsPropertyName) : FieldsPropertyName); writer.WriteStartArray(); @@ -148,30 +166,30 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { return null; } - UnionCase caseInfo = null; - string caseName = null; - JArray fields = null; + UnionCase? caseInfo = null; + string? caseName = null; + JArray? fields = null; // start object reader.ReadAndAssert(); while (reader.TokenType == JsonToken.PropertyName) { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (string.Equals(propertyName, CasePropertyName, StringComparison.OrdinalIgnoreCase)) { reader.ReadAndAssert(); Union union = UnionCache.Get(objectType); - caseName = reader.Value.ToString(); + caseName = reader.Value!.ToString(); caseInfo = union.Cases.SingleOrDefault(c => c.Name == caseName); @@ -203,7 +221,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "No '{0}' property with union name found.".FormatWith(CultureInfo.InvariantCulture, CasePropertyName)); } - object[] typedFieldValues = new object[caseInfo.Fields.Length]; + object?[] typedFieldValues = new object?[caseInfo.Fields.Length]; if (caseInfo.Fields.Length > 0 && fields == null) { @@ -272,7 +290,7 @@ public override bool CanConvert(Type objectType) return false; } - return (bool)FSharpUtils.IsUnion(null, objectType, null); + return (bool)FSharpUtils.Instance.IsUnion(null, objectType, null); } } } diff --git a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs index aeeb87a06..757c8fac6 100644 --- a/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs +++ b/Src/Newtonsoft.Json/Converters/EntityKeyMemberConverter.cs @@ -28,6 +28,7 @@ using Newtonsoft.Json.Serialization; using System.Globalization; using Newtonsoft.Json.Utilities; +using System.Diagnostics; namespace Newtonsoft.Json.Converters { @@ -42,7 +43,7 @@ public class EntityKeyMemberConverter : JsonConverter private const string TypePropertyName = "Type"; private const string ValuePropertyName = "Value"; - private static ReflectionObject _reflectionObject; + private static ReflectionObject? _reflectionObject; /// /// Writes the JSON representation of the object. @@ -50,16 +51,23 @@ public class EntityKeyMemberConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { + if (value == null) + { + writer.WriteNull(); + return; + } + EnsureReflectionObject(value.GetType()); + MiscellaneousUtils.Assert(_reflectionObject != null); - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; - string keyName = (string)_reflectionObject.GetValue(value, KeyPropertyName); - object keyValue = _reflectionObject.GetValue(value, ValuePropertyName); + string keyName = (string)_reflectionObject.GetValue(value, KeyPropertyName)!; + object? keyValue = _reflectionObject.GetValue(value, ValuePropertyName); - Type keyValueType = keyValue?.GetType(); + Type? keyValueType = keyValue?.GetType(); writer.WriteStartObject(); writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyPropertyName) : KeyPropertyName); @@ -71,7 +79,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s if (keyValueType != null) { - if (JsonSerializerInternalWriter.TryConvertToString(keyValue, keyValueType, out string valueJson)) + if (JsonSerializerInternalWriter.TryConvertToString(keyValue!, keyValueType, out string? valueJson)) { writer.WriteValue(valueJson); } @@ -92,7 +100,7 @@ private static void ReadAndAssertProperty(JsonReader reader, string propertyName { reader.ReadAndAssert(); - if (reader.TokenType != JsonToken.PropertyName || !string.Equals(reader.Value.ToString(), propertyName, StringComparison.OrdinalIgnoreCase)) + if (reader.TokenType != JsonToken.PropertyName || !string.Equals(reader.Value?.ToString(), propertyName, StringComparison.OrdinalIgnoreCase)) { throw new JsonSerializationException("Expected JSON property '{0}'.".FormatWith(CultureInfo.InvariantCulture, propertyName)); } @@ -106,21 +114,22 @@ private static void ReadAndAssertProperty(JsonReader reader, string propertyName /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { EnsureReflectionObject(objectType); + MiscellaneousUtils.Assert(_reflectionObject != null); - object entityKeyMember = _reflectionObject.Creator(); + object entityKeyMember = _reflectionObject.Creator!(); ReadAndAssertProperty(reader, KeyPropertyName); reader.ReadAndAssert(); - _reflectionObject.SetValue(entityKeyMember, KeyPropertyName, reader.Value.ToString()); + _reflectionObject.SetValue(entityKeyMember, KeyPropertyName, reader.Value?.ToString()); ReadAndAssertProperty(reader, TypePropertyName); reader.ReadAndAssert(); - string type = reader.Value.ToString(); + string? type = reader.Value?.ToString(); - Type t = Type.GetType(type); + Type t = Type.GetType(type!)!; ReadAndAssertProperty(reader, ValuePropertyName); reader.ReadAndAssert(); diff --git a/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs b/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs index c946692b8..5a674b8c1 100644 --- a/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs +++ b/Src/Newtonsoft.Json/Converters/ExpandoObjectConverter.cs @@ -46,7 +46,7 @@ public class ExpandoObjectConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { // can write is set to false } @@ -59,12 +59,12 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { return ReadValue(reader); } - private object ReadValue(JsonReader reader) + private object? ReadValue(JsonReader reader) { if (!reader.MoveToContent()) { @@ -89,7 +89,7 @@ private object ReadValue(JsonReader reader) private object ReadList(JsonReader reader) { - IList list = new List(); + IList list = new List(); while (reader.Read()) { @@ -98,7 +98,7 @@ private object ReadList(JsonReader reader) case JsonToken.Comment: break; default: - object v = ReadValue(reader); + object? v = ReadValue(reader); list.Add(v); break; @@ -112,21 +112,21 @@ private object ReadList(JsonReader reader) private object ReadObject(JsonReader reader) { - IDictionary expandoObject = new ExpandoObject(); + IDictionary expandoObject = new ExpandoObject(); while (reader.Read()) { switch (reader.TokenType) { case JsonToken.PropertyName: - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (!reader.Read()) { throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject."); } - object v = ReadValue(reader); + object? v = ReadValue(reader); expandoObject[propertyName] = v; break; diff --git a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs index 5a2e9322e..de9b1bb59 100644 --- a/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs @@ -37,8 +37,8 @@ public class IsoDateTimeConverter : DateTimeConverterBase private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; - private string _dateTimeFormat; - private CultureInfo _culture; + private string? _dateTimeFormat; + private CultureInfo? _culture; /// /// Gets or sets the date time styles used when converting a date to and from JSON. @@ -54,10 +54,10 @@ public DateTimeStyles DateTimeStyles /// Gets or sets the date time format used when converting a date to and from JSON. /// /// The date time format used when converting a date to and from JSON. - public string DateTimeFormat + public string? DateTimeFormat { get => _dateTimeFormat ?? string.Empty; - set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value; + set => _dateTimeFormat = (StringUtils.IsNullOrEmpty(value)) ? null : value; } /// @@ -76,7 +76,7 @@ public CultureInfo Culture /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { string text; @@ -104,7 +104,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s #endif else { - throw new JsonSerializationException("Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {0}.".FormatWith(CultureInfo.InvariantCulture, ReflectionUtils.GetObjectType(value))); + throw new JsonSerializationException("Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {0}.".FormatWith(CultureInfo.InvariantCulture, ReflectionUtils.GetObjectType(value)!)); } writer.WriteValue(text); @@ -118,7 +118,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { bool nullable = ReflectionUtils.IsNullableType(objectType); if (reader.TokenType == JsonToken.Null) @@ -133,7 +133,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_DATE_TIME_OFFSET Type t = (nullable) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; #endif @@ -142,7 +142,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_DATE_TIME_OFFSET if (t == typeof(DateTimeOffset)) { - return (reader.Value is DateTimeOffset) ? reader.Value : new DateTimeOffset((DateTime)reader.Value); + return (reader.Value is DateTimeOffset) ? reader.Value : new DateTimeOffset((DateTime)reader.Value!); } // converter is expected to return a DateTime @@ -160,17 +160,19 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - string dateText = reader.Value.ToString(); + string? dateText = reader.Value?.ToString(); - if (string.IsNullOrEmpty(dateText) && nullable) + if (StringUtils.IsNullOrEmpty(dateText) && nullable) { return null; } + MiscellaneousUtils.Assert(dateText != null); + #if HAVE_DATE_TIME_OFFSET if (t == typeof(DateTimeOffset)) { - if (!string.IsNullOrEmpty(_dateTimeFormat)) + if (!StringUtils.IsNullOrEmpty(_dateTimeFormat)) { return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); } @@ -181,7 +183,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } #endif - if (!string.IsNullOrEmpty(_dateTimeFormat)) + if (!StringUtils.IsNullOrEmpty(_dateTimeFormat)) { return DateTime.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles); } diff --git a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs index 24194b764..ff1231f25 100644 --- a/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/JavaScriptDateTimeConverter.cs @@ -40,7 +40,7 @@ public class JavaScriptDateTimeConverter : DateTimeConverterBase /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { long ticks; @@ -74,7 +74,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -86,19 +86,19 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return null; } - if (reader.TokenType != JsonToken.StartConstructor || !string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (reader.TokenType != JsonToken.StartConstructor || !string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { throw JsonSerializationException.Create(reader, "Unexpected token or value when parsing date. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value)); } - if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime d, out string errorMessage)) + if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime d, out string? errorMessage)) { throw JsonSerializationException.Create(reader, errorMessage); } #if HAVE_DATE_TIME_OFFSET Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; if (t == typeof(DateTimeOffset)) { diff --git a/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs b/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs index 2d4197032..0221e9337 100644 --- a/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs +++ b/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs @@ -56,11 +56,17 @@ private static ReflectionObject InitializeReflectionObject(Type t) /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { + if (value == null) + { + writer.WriteNull(); + return; + } + ReflectionObject reflectionObject = ReflectionObjectPerType.Get(value.GetType()); - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; writer.WriteStartObject(); writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyName) : KeyName); @@ -78,7 +84,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -90,13 +96,13 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return null; } - object key = null; - object value = null; + object? key = null; + object? value = null; reader.ReadAndAssert(); Type t = ReflectionUtils.IsNullableType(objectType) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; ReflectionObject reflectionObject = ReflectionObjectPerType.Get(t); @@ -105,7 +111,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist while (reader.TokenType == JsonToken.PropertyName) { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (string.Equals(propertyName, KeyName, StringComparison.OrdinalIgnoreCase)) { reader.ReadForTypeAndAssert(keyContract, false); @@ -126,7 +132,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist reader.ReadAndAssert(); } - return reflectionObject.Creator(key, value); + return reflectionObject.Creator!(key, value); } /// @@ -139,7 +145,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override bool CanConvert(Type objectType) { Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; if (t.IsValueType() && t.IsGenericType()) diff --git a/Src/Newtonsoft.Json/Converters/RegexConverter.cs b/Src/Newtonsoft.Json/Converters/RegexConverter.cs index 719a06ad6..13db1bb57 100644 --- a/Src/Newtonsoft.Json/Converters/RegexConverter.cs +++ b/Src/Newtonsoft.Json/Converters/RegexConverter.cs @@ -47,7 +47,7 @@ public class RegexConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -84,7 +84,7 @@ private void WriteBson(BsonWriter writer, Regex regex) // 'l' to make \w, \W, etc. locale dependent, 's' for dotall mode // ('.' matches everything), and 'u' to make \w, \W, etc. match unicode. - string options = null; + string? options = null; if (HasFlag(regex.Options, RegexOptions.IgnoreCase)) { @@ -114,7 +114,7 @@ private void WriteBson(BsonWriter writer, Regex regex) private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer) { - DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver; + DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver; writer.WriteStartObject(); writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(PatternName) : PatternName); @@ -132,7 +132,7 @@ private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { switch (reader.TokenType) { @@ -149,7 +149,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist private object ReadRegexString(JsonReader reader) { - string regexText = (string)reader.Value; + string regexText = (string)reader.Value!; if (regexText.Length > 0 && regexText[0] == '/') { @@ -171,7 +171,7 @@ private object ReadRegexString(JsonReader reader) private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer) { - string pattern = null; + string? pattern = null; RegexOptions? options = null; while (reader.Read()) @@ -179,7 +179,7 @@ private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer) switch (reader.TokenType) { case JsonToken.PropertyName: - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (!reader.Read()) { @@ -188,7 +188,7 @@ private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer) if (string.Equals(propertyName, PatternName, StringComparison.OrdinalIgnoreCase)) { - pattern = (string)reader.Value; + pattern = (string?)reader.Value; } else if (string.Equals(propertyName, OptionsName, StringComparison.OrdinalIgnoreCase)) { diff --git a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs index 6639235e2..a98400808 100644 --- a/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs +++ b/Src/Newtonsoft.Json/Converters/StringEnumConverter.cs @@ -82,7 +82,7 @@ public bool CamelCaseText /// Gets or sets the naming strategy used to resolve how enum text is written. /// /// The naming strategy used to resolve how enum text is written. - public NamingStrategy NamingStrategy { get; set; } + public NamingStrategy? NamingStrategy { get; set; } /// /// Gets or sets a value indicating whether integer values are allowed when serializing and deserializing. @@ -175,7 +175,7 @@ public StringEnumConverter(Type namingStrategyType, object[] namingStrategyParam /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -185,7 +185,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s Enum e = (Enum)value; - if (!EnumUtils.TryToString(e.GetType(), value, NamingStrategy, out string enumName)) + if (!EnumUtils.TryToString(e.GetType(), value, NamingStrategy, out string? enumName)) { if (!AllowIntegerValues) { @@ -209,7 +209,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -222,20 +222,20 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } bool isNullable = ReflectionUtils.IsNullableType(objectType); - Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType; + Type t = isNullable ? Nullable.GetUnderlyingType(objectType)! : objectType; try { if (reader.TokenType == JsonToken.String) { - string enumText = reader.Value.ToString(); + string? enumText = reader.Value?.ToString(); - if (enumText == string.Empty && isNullable) + if (StringUtils.IsNullOrEmpty(enumText) && isNullable) { return null; } - return EnumUtils.ParseEnum(t, NamingStrategy, enumText, !AllowIntegerValues); + return EnumUtils.ParseEnum(t, NamingStrategy, enumText!, !AllowIntegerValues); } if (reader.TokenType == JsonToken.Integer) @@ -267,7 +267,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override bool CanConvert(Type objectType) { Type t = (ReflectionUtils.IsNullableType(objectType)) - ? Nullable.GetUnderlyingType(objectType) + ? Nullable.GetUnderlyingType(objectType)! : objectType; return t.IsEnum(); diff --git a/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs b/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs index c5b03bb5c..7d0700e0c 100644 --- a/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/UnixDateTimeConverter.cs @@ -36,13 +36,44 @@ public class UnixDateTimeConverter : DateTimeConverterBase { internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + /// + /// Gets or sets a value indicating whether the dates before Unix epoch + /// should converted to and from JSON. + /// + /// + /// true to allow converting dates before Unix epoch to and from JSON; + /// false to throw an exception when a date being converted to or from JSON + /// occurred before Unix epoch. The default value is false. + /// + public bool AllowPreEpoch { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public UnixDateTimeConverter() : this(false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// true to allow converting dates before Unix epoch to and from JSON; + /// false to throw an exception when a date being converted to or from JSON + /// occurred before Unix epoch. The default value is false. + /// + public UnixDateTimeConverter(bool allowPreEpoch) + { + AllowPreEpoch = allowPreEpoch; + } + /// /// Writes the JSON representation of the object. /// /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { long seconds; @@ -61,7 +92,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s throw new JsonSerializationException("Expected date object value."); } - if (seconds < 0) + if (!AllowPreEpoch && seconds < 0) { throw new JsonSerializationException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970."); } @@ -77,7 +108,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { bool nullable = ReflectionUtils.IsNullable(objectType); if (reader.TokenType == JsonToken.Null) @@ -94,11 +125,11 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist if (reader.TokenType == JsonToken.Integer) { - seconds = (long)reader.Value; + seconds = (long)reader.Value!; } else if (reader.TokenType == JsonToken.String) { - if (!long.TryParse((string)reader.Value, out seconds)) + if (!long.TryParse((string)reader.Value!, out seconds)) { throw JsonSerializationException.Create(reader, "Cannot convert invalid value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType)); } @@ -108,12 +139,12 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected Integer or String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - if (seconds >= 0) + if (AllowPreEpoch || seconds >= 0) { DateTime d = UnixEpoch.AddSeconds(seconds); #if HAVE_DATE_TIME_OFFSET - Type t = (nullable) + Type? t = (nullable) ? Nullable.GetUnderlyingType(objectType) : objectType; if (t == typeof(DateTimeOffset)) diff --git a/Src/Newtonsoft.Json/Converters/VersionConverter.cs b/Src/Newtonsoft.Json/Converters/VersionConverter.cs index df52718f1..e0cded265 100644 --- a/Src/Newtonsoft.Json/Converters/VersionConverter.cs +++ b/Src/Newtonsoft.Json/Converters/VersionConverter.cs @@ -40,7 +40,7 @@ public class VersionConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -64,7 +64,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s /// The existing property value of the JSON that is being converted. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { @@ -76,7 +76,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist { try { - Version v = new Version((string)reader.Value); + Version v = new Version((string)reader.Value!); return v; } catch (Exception ex) diff --git a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs index 6e7ba0597..12bde5157 100644 --- a/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs +++ b/Src/Newtonsoft.Json/Converters/XmlNodeConverter.cs @@ -38,6 +38,7 @@ #endif using Newtonsoft.Json.Utilities; using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Newtonsoft.Json.Converters { @@ -53,38 +54,38 @@ public XmlDocumentWrapper(XmlDocument document) _document = document; } - public IXmlNode CreateComment(string data) + public IXmlNode CreateComment(string? data) { return new XmlNodeWrapper(_document.CreateComment(data)); } - public IXmlNode CreateTextNode(string text) + public IXmlNode CreateTextNode(string? text) { return new XmlNodeWrapper(_document.CreateTextNode(text)); } - public IXmlNode CreateCDataSection(string data) + public IXmlNode CreateCDataSection(string? data) { return new XmlNodeWrapper(_document.CreateCDataSection(data)); } - public IXmlNode CreateWhitespace(string text) + public IXmlNode CreateWhitespace(string? text) { return new XmlNodeWrapper(_document.CreateWhitespace(text)); } - public IXmlNode CreateSignificantWhitespace(string text) + public IXmlNode CreateSignificantWhitespace(string? text) { return new XmlNodeWrapper(_document.CreateSignificantWhitespace(text)); } - public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone) + public IXmlNode CreateXmlDeclaration(string version, string? encoding, string? standalone) { return new XmlDeclarationWrapper(_document.CreateXmlDeclaration(version, encoding, standalone)); } #if HAVE_XML_DOCUMENT_TYPE - public IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset) + public IXmlNode CreateXmlDocumentType(string name, string? publicId, string? systemId, string? internalSubset) { return new XmlDocumentTypeWrapper(_document.CreateDocumentType(name, publicId, systemId, null)); } @@ -105,7 +106,7 @@ public IXmlElement CreateElement(string qualifiedName, string namespaceUri) return new XmlElementWrapper(_document.CreateElement(qualifiedName, namespaceUri)); } - public IXmlNode CreateAttribute(string name, string value) + public IXmlNode CreateAttribute(string name, string? value) { XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(name)); attribute.Value = value; @@ -113,7 +114,7 @@ public IXmlNode CreateAttribute(string name, string value) return attribute; } - public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value) + public IXmlNode CreateAttribute(string qualifiedName, string? namespaceUri, string? value) { XmlNodeWrapper attribute = new XmlNodeWrapper(_document.CreateAttribute(qualifiedName, namespaceUri)); attribute.Value = value; @@ -121,7 +122,7 @@ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, strin return attribute; } - public IXmlElement DocumentElement + public IXmlElement? DocumentElement { get { @@ -149,10 +150,10 @@ public void SetAttributeNode(IXmlNode attribute) { XmlNodeWrapper xmlAttributeWrapper = (XmlNodeWrapper)attribute; - _element.SetAttributeNode((XmlAttribute)xmlAttributeWrapper.WrappedNode); + _element.SetAttributeNode((XmlAttribute)xmlAttributeWrapper.WrappedNode!); } - public string GetPrefixOfNamespace(string namespaceUri) + public string? GetPrefixOfNamespace(string namespaceUri) { return _element.GetPrefixOfNamespace(namespaceUri); } @@ -170,15 +171,15 @@ public XmlDeclarationWrapper(XmlDeclaration declaration) _declaration = declaration; } - public string Version => _declaration.Version; + public string? Version => _declaration.Version; - public string Encoding + public string? Encoding { get => _declaration.Encoding; set => _declaration.Encoding = value; } - public string Standalone + public string? Standalone { get => _declaration.Standalone; set => _declaration.Standalone = value; @@ -198,32 +199,32 @@ public XmlDocumentTypeWrapper(XmlDocumentType documentType) public string Name => _documentType.Name; - public string System => _documentType.SystemId; + public string? System => _documentType.SystemId; - public string Public => _documentType.PublicId; + public string? Public => _documentType.PublicId; - public string InternalSubset => _documentType.InternalSubset; + public string? InternalSubset => _documentType.InternalSubset; - public override string LocalName => "DOCTYPE"; + public override string? LocalName => "DOCTYPE"; } #endif internal class XmlNodeWrapper : IXmlNode { private readonly XmlNode _node; - private List _childNodes; - private List _attributes; + private List? _childNodes; + private List? _attributes; public XmlNodeWrapper(XmlNode node) { _node = node; } - public object WrappedNode => _node; + public object? WrappedNode => _node; public XmlNodeType NodeType => _node.NodeType; - public virtual string LocalName => _node.LocalName; + public virtual string? LocalName => _node.LocalName; public List ChildNodes { @@ -284,7 +285,7 @@ public List Attributes } else { - _attributes = new List(_node.Attributes.Count); + _attributes = new List(_node.Attributes!.Count); foreach (XmlAttribute attribute in _node.Attributes) { _attributes.Add(WrapNode(attribute)); @@ -309,11 +310,11 @@ private bool HasAttributes } } - public IXmlNode ParentNode + public IXmlNode? ParentNode { get { - XmlNode node = _node is XmlAttribute attribute ? attribute.OwnerElement : _node.ParentNode; + XmlNode? node = _node is XmlAttribute attribute ? attribute.OwnerElement : _node.ParentNode; if (node == null) { @@ -324,7 +325,7 @@ public IXmlNode ParentNode } } - public string Value + public string? Value { get => _node.Value; set => _node.Value = value; @@ -340,7 +341,7 @@ public IXmlNode AppendChild(IXmlNode newChild) return newChild; } - public string NamespaceUri => _node.NamespaceURI; + public string? NamespaceUri => _node.NamespaceURI; } #endif #endregion @@ -348,14 +349,14 @@ public IXmlNode AppendChild(IXmlNode newChild) #region Interfaces internal interface IXmlDocument : IXmlNode { - IXmlNode CreateComment(string text); - IXmlNode CreateTextNode(string text); - IXmlNode CreateCDataSection(string data); - IXmlNode CreateWhitespace(string text); - IXmlNode CreateSignificantWhitespace(string text); - IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone); + IXmlNode CreateComment(string? text); + IXmlNode CreateTextNode(string? text); + IXmlNode CreateCDataSection(string? data); + IXmlNode CreateWhitespace(string? text); + IXmlNode CreateSignificantWhitespace(string? text); + IXmlNode CreateXmlDeclaration(string version, string? encoding, string? standalone); #if HAVE_XML_DOCUMENT_TYPE - IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset); + IXmlNode CreateXmlDocumentType(string name, string? publicId, string? systemId, string? internalSubset); #endif IXmlNode CreateProcessingInstruction(string target, string data); IXmlElement CreateElement(string elementName); @@ -363,42 +364,42 @@ internal interface IXmlDocument : IXmlNode IXmlNode CreateAttribute(string name, string value); IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, string value); - IXmlElement DocumentElement { get; } + IXmlElement? DocumentElement { get; } } internal interface IXmlDeclaration : IXmlNode { - string Version { get; } - string Encoding { get; set; } - string Standalone { get; set; } + string? Version { get; } + string? Encoding { get; set; } + string? Standalone { get; set; } } internal interface IXmlDocumentType : IXmlNode { string Name { get; } - string System { get; } - string Public { get; } - string InternalSubset { get; } + string? System { get; } + string? Public { get; } + string? InternalSubset { get; } } internal interface IXmlElement : IXmlNode { void SetAttributeNode(IXmlNode attribute); - string GetPrefixOfNamespace(string namespaceUri); + string? GetPrefixOfNamespace(string namespaceUri); bool IsEmpty { get; } } internal interface IXmlNode { XmlNodeType NodeType { get; } - string LocalName { get; } + string? LocalName { get; } List ChildNodes { get; } List Attributes { get; } - IXmlNode ParentNode { get; } - string Value { get; set; } + IXmlNode? ParentNode { get; } + string? Value { get; set; } IXmlNode AppendChild(IXmlNode newChild); - string NamespaceUri { get; } - object WrappedNode { get; } + string? NamespaceUri { get; } + object? WrappedNode { get; } } #endregion @@ -416,15 +417,15 @@ public XDeclarationWrapper(XDeclaration declaration) public override XmlNodeType NodeType => XmlNodeType.XmlDeclaration; - public string Version => Declaration.Version; + public string? Version => Declaration.Version; - public string Encoding + public string? Encoding { get => Declaration.Encoding; set => Declaration.Encoding = value; } - public string Standalone + public string? Standalone { get => Declaration.Standalone; set => Declaration.Standalone = value; @@ -443,18 +444,18 @@ public XDocumentTypeWrapper(XDocumentType documentType) public string Name => _documentType.Name; - public string System => _documentType.SystemId; + public string? System => _documentType.SystemId; - public string Public => _documentType.PublicId; + public string? Public => _documentType.PublicId; - public string InternalSubset => _documentType.InternalSubset; + public string? InternalSubset => _documentType.InternalSubset; - public override string LocalName => "DOCTYPE"; + public override string? LocalName => "DOCTYPE"; } internal class XDocumentWrapper : XContainerWrapper, IXmlDocument { - private XDocument Document => (XDocument)WrappedNode; + private XDocument Document => (XDocument)WrappedNode!; public XDocumentWrapper(XDocument document) : base(document) @@ -488,37 +489,37 @@ protected override bool HasChildNodes } } - public IXmlNode CreateComment(string text) + public IXmlNode CreateComment(string? text) { - return new XObjectWrapper(new XComment(text)); + return new XObjectWrapper(new XComment(text!)); } - public IXmlNode CreateTextNode(string text) + public IXmlNode CreateTextNode(string? text) { - return new XObjectWrapper(new XText(text)); + return new XObjectWrapper(new XText(text!)); } - public IXmlNode CreateCDataSection(string data) + public IXmlNode CreateCDataSection(string? data) { - return new XObjectWrapper(new XCData(data)); + return new XObjectWrapper(new XCData(data!)); } - public IXmlNode CreateWhitespace(string text) + public IXmlNode CreateWhitespace(string? text) { - return new XObjectWrapper(new XText(text)); + return new XObjectWrapper(new XText(text!)); } - public IXmlNode CreateSignificantWhitespace(string text) + public IXmlNode CreateSignificantWhitespace(string? text) { - return new XObjectWrapper(new XText(text)); + return new XObjectWrapper(new XText(text!)); } - public IXmlNode CreateXmlDeclaration(string version, string encoding, string standalone) + public IXmlNode CreateXmlDeclaration(string version, string? encoding, string? standalone) { return new XDeclarationWrapper(new XDeclaration(version, encoding, standalone)); } - public IXmlNode CreateXmlDocumentType(string name, string publicId, string systemId, string internalSubset) + public IXmlNode CreateXmlDocumentType(string name, string? publicId, string? systemId, string? internalSubset) { return new XDocumentTypeWrapper(new XDocumentType(name, publicId, systemId, internalSubset)); } @@ -550,7 +551,7 @@ public IXmlNode CreateAttribute(string qualifiedName, string namespaceUri, strin return new XAttributeWrapper(new XAttribute(XName.Get(localName, namespaceUri), value)); } - public IXmlElement DocumentElement + public IXmlElement? DocumentElement { get { @@ -579,20 +580,20 @@ public override IXmlNode AppendChild(IXmlNode newChild) internal class XTextWrapper : XObjectWrapper { - private XText Text => (XText)WrappedNode; + private XText Text => (XText)WrappedNode!; public XTextWrapper(XText text) : base(text) { } - public override string Value + public override string? Value { get => Text.Value; - set => Text.Value = value; + set => Text.Value = value ?? string.Empty; } - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -608,20 +609,20 @@ public override IXmlNode ParentNode internal class XCommentWrapper : XObjectWrapper { - private XComment Text => (XComment)WrappedNode; + private XComment Text => (XComment)WrappedNode!; public XCommentWrapper(XComment text) : base(text) { } - public override string Value + public override string? Value { get => Text.Value; - set => Text.Value = value; + set => Text.Value = value ?? string.Empty; } - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -637,27 +638,27 @@ public override IXmlNode ParentNode internal class XProcessingInstructionWrapper : XObjectWrapper { - private XProcessingInstruction ProcessingInstruction => (XProcessingInstruction)WrappedNode; + private XProcessingInstruction ProcessingInstruction => (XProcessingInstruction)WrappedNode!; public XProcessingInstructionWrapper(XProcessingInstruction processingInstruction) : base(processingInstruction) { } - public override string LocalName => ProcessingInstruction.Target; + public override string? LocalName => ProcessingInstruction.Target; - public override string Value + public override string? Value { get => ProcessingInstruction.Data; - set => ProcessingInstruction.Data = value; + set => ProcessingInstruction.Data = value ?? string.Empty; } } internal class XContainerWrapper : XObjectWrapper { - private List _childNodes; + private List? _childNodes; - private XContainer Container => (XContainer)WrappedNode; + private XContainer Container => (XContainer)WrappedNode!; public XContainerWrapper(XContainer container) : base(container) @@ -692,7 +693,7 @@ public override List ChildNodes protected virtual bool HasChildNodes => Container.LastNode != null; - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -761,26 +762,26 @@ public override IXmlNode AppendChild(IXmlNode newChild) internal class XObjectWrapper : IXmlNode { - private readonly XObject _xmlObject; + private readonly XObject? _xmlObject; - public XObjectWrapper(XObject xmlObject) + public XObjectWrapper(XObject? xmlObject) { _xmlObject = xmlObject; } - public object WrappedNode => _xmlObject; + public object? WrappedNode => _xmlObject; - public virtual XmlNodeType NodeType => _xmlObject.NodeType; + public virtual XmlNodeType NodeType => _xmlObject?.NodeType ?? XmlNodeType.None; - public virtual string LocalName => null; + public virtual string? LocalName => null; public virtual List ChildNodes => XmlNodeConverter.EmptyChildNodes; public virtual List Attributes => XmlNodeConverter.EmptyChildNodes; - public virtual IXmlNode ParentNode => null; + public virtual IXmlNode? ParentNode => null; - public virtual string Value + public virtual string? Value { get => null; set => throw new InvalidOperationException(); @@ -791,29 +792,29 @@ public virtual IXmlNode AppendChild(IXmlNode newChild) throw new InvalidOperationException(); } - public virtual string NamespaceUri => null; + public virtual string? NamespaceUri => null; } internal class XAttributeWrapper : XObjectWrapper { - private XAttribute Attribute => (XAttribute)WrappedNode; + private XAttribute Attribute => (XAttribute)WrappedNode!; public XAttributeWrapper(XAttribute attribute) : base(attribute) { } - public override string Value + public override string? Value { get => Attribute.Value; - set => Attribute.Value = value; + set => Attribute.Value = value ?? string.Empty; } - public override string LocalName => Attribute.Name.LocalName; + public override string? LocalName => Attribute.Name.LocalName; - public override string NamespaceUri => Attribute.Name.NamespaceName; + public override string? NamespaceUri => Attribute.Name.NamespaceName; - public override IXmlNode ParentNode + public override IXmlNode? ParentNode { get { @@ -829,9 +830,9 @@ public override IXmlNode ParentNode internal class XElementWrapper : XContainerWrapper, IXmlElement { - private List _attributes; + private List? _attributes; - private XElement Element => (XElement)WrappedNode; + private XElement Element => (XElement)WrappedNode!; public XElementWrapper(XElement element) : base(element) @@ -853,7 +854,7 @@ public override List Attributes // cache results to prevent multiple reads which kills perf in large documents if (_attributes == null) { - if (!Element.HasAttributes && !HasImplicitNamespaceAttribute(NamespaceUri)) + if (!Element.HasAttributes && !HasImplicitNamespaceAttribute(NamespaceUri!)) { _attributes = XmlNodeConverter.EmptyChildNodes; } @@ -867,7 +868,7 @@ public override List Attributes // ensure elements created with a namespace but no namespace attribute are converted correctly // e.g. new XElement("{http://example.com}MyElement"); - string namespaceUri = NamespaceUri; + string namespaceUri = NamespaceUri!; if (HasImplicitNamespaceAttribute(namespaceUri)) { _attributes.Insert(0, new XAttributeWrapper(new XAttribute("xmlns", namespaceUri))); @@ -881,9 +882,9 @@ public override List Attributes private bool HasImplicitNamespaceAttribute(string namespaceUri) { - if (!string.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri) + if (!StringUtils.IsNullOrEmpty(namespaceUri) && namespaceUri != ParentNode?.NamespaceUri) { - if (string.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri))) + if (StringUtils.IsNullOrEmpty(GetPrefixOfNamespace(namespaceUri))) { bool namespaceDeclared = false; @@ -891,7 +892,7 @@ private bool HasImplicitNamespaceAttribute(string namespaceUri) { foreach (XAttribute attribute in Element.Attributes()) { - if (attribute.Name.LocalName == "xmlns" && string.IsNullOrEmpty(attribute.Name.NamespaceName) && attribute.Value == namespaceUri) + if (attribute.Name.LocalName == "xmlns" && StringUtils.IsNullOrEmpty(attribute.Name.NamespaceName) && attribute.Value == namespaceUri) { namespaceDeclared = true; } @@ -915,17 +916,17 @@ public override IXmlNode AppendChild(IXmlNode newChild) return result; } - public override string Value + public override string? Value { get => Element.Value; - set => Element.Value = value; + set => Element.Value = value ?? string.Empty; } - public override string LocalName => Element.Name.LocalName; + public override string? LocalName => Element.Name.LocalName; - public override string NamespaceUri => Element.Name.NamespaceName; + public override string? NamespaceUri => Element.Name.NamespaceName; - public string GetPrefixOfNamespace(string namespaceUri) + public string? GetPrefixOfNamespace(string namespaceUri) { return Element.GetPrefixOfNamespace(namespaceUri); } @@ -954,7 +955,7 @@ public class XmlNodeConverter : JsonConverter /// Gets or sets the name of the root element to insert when deserializing to XML if the JSON structure has produced multiple root elements. /// /// The name of the deserialized root element. - public string DeserializeRootElementName { get; set; } + public string? DeserializeRootElementName { get; set; } /// /// Gets or sets a value to indicate whether to write the Json.NET array attribute. @@ -985,7 +986,7 @@ public class XmlNodeConverter : JsonConverter /// The to write to. /// The calling serializer. /// The value. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { @@ -1031,9 +1032,9 @@ private IXmlNode WrapXml(object value) private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager) { - List parentElements = null; + List? parentElements = null; - IXmlNode parent = node; + IXmlNode? parent = node; while ((parent = parent.ParentNode) != null) { if (parent.NodeType == XmlNodeType.Element) @@ -1058,7 +1059,7 @@ private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager) { if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/" && attribute.LocalName != "xmlns") { - manager.AddNamespace(attribute.LocalName, attribute.Value); + manager.AddNamespace(attribute.LocalName!, attribute.Value!); } } } @@ -1067,17 +1068,17 @@ private void PushParentNamespaces(IXmlNode node, XmlNamespaceManager manager) private string ResolveFullName(IXmlNode node, XmlNamespaceManager manager) { - string prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/")) + string? prefix = (node.NamespaceUri == null || (node.LocalName == "xmlns" && node.NamespaceUri == "http://www.w3.org/2000/xmlns/")) ? null : manager.LookupPrefix(node.NamespaceUri); - if (!string.IsNullOrEmpty(prefix)) + if (!StringUtils.IsNullOrEmpty(prefix)) { return prefix + ":" + XmlConvert.DecodeName(node.LocalName); } else { - return XmlConvert.DecodeName(node.LocalName); + return XmlConvert.DecodeName(node.LocalName)!; } } @@ -1130,7 +1131,7 @@ private bool IsArray(IXmlNode node) { if (attribute.LocalName == "Array" && attribute.NamespaceUri == JsonNamespaceUri) { - return XmlConvert.ToBoolean(attribute.Value); + return XmlConvert.ToBoolean(attribute.Value!); } } @@ -1160,9 +1161,9 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac // value of dictionary will be a single IXmlNode when there is one for a name, // or a List when there are multiple - Dictionary nodesGroupedByName = null; + Dictionary? nodesGroupedByName = null; - string nodeName = null; + string? nodeName = null; for (int i = 0; i < node.ChildNodes.Count; i++) { @@ -1200,7 +1201,7 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac } else { - if (!nodesGroupedByName.TryGetValue(currentNodeName, out object value)) + if (!nodesGroupedByName.TryGetValue(currentNodeName, out object? value)) { nodesGroupedByName.Add(currentNodeName, childNode); } @@ -1208,7 +1209,7 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac { if (!(value is List nodes)) { - nodes = new List {(IXmlNode)value}; + nodes = new List {(IXmlNode)value!}; nodesGroupedByName[currentNodeName] = nodes; } @@ -1219,7 +1220,7 @@ private void SerializeGroupedNodes(JsonWriter writer, IXmlNode node, XmlNamespac if (nodesGroupedByName == null) { - WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName); + WriteGroupedNodes(writer, manager, writePropertyName, node.ChildNodes, nodeName!); } else { @@ -1313,9 +1314,13 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager if (attribute.NamespaceUri == "http://www.w3.org/2000/xmlns/") { string namespacePrefix = (attribute.LocalName != "xmlns") - ? XmlConvert.DecodeName(attribute.LocalName) + ? XmlConvert.DecodeName(attribute.LocalName)! : string.Empty; - string namespaceUri = attribute.Value; + string? namespaceUri = attribute.Value; + if (namespaceUri == null) + { + throw new JsonSerializationException("Namespace attribute must have a value."); + } manager.AddNamespace(namespacePrefix, namespaceUri); } @@ -1400,17 +1405,17 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager writer.WritePropertyName(GetPropertyName(node, manager)); writer.WriteStartObject(); - if (!string.IsNullOrEmpty(declaration.Version)) + if (!StringUtils.IsNullOrEmpty(declaration.Version)) { writer.WritePropertyName("@version"); writer.WriteValue(declaration.Version); } - if (!string.IsNullOrEmpty(declaration.Encoding)) + if (!StringUtils.IsNullOrEmpty(declaration.Encoding)) { writer.WritePropertyName("@encoding"); writer.WriteValue(declaration.Encoding); } - if (!string.IsNullOrEmpty(declaration.Standalone)) + if (!StringUtils.IsNullOrEmpty(declaration.Standalone)) { writer.WritePropertyName("@standalone"); writer.WriteValue(declaration.Standalone); @@ -1423,22 +1428,22 @@ private void SerializeNode(JsonWriter writer, IXmlNode node, XmlNamespaceManager writer.WritePropertyName(GetPropertyName(node, manager)); writer.WriteStartObject(); - if (!string.IsNullOrEmpty(documentType.Name)) + if (!StringUtils.IsNullOrEmpty(documentType.Name)) { writer.WritePropertyName("@name"); writer.WriteValue(documentType.Name); } - if (!string.IsNullOrEmpty(documentType.Public)) + if (!StringUtils.IsNullOrEmpty(documentType.Public)) { writer.WritePropertyName("@public"); writer.WriteValue(documentType.Public); } - if (!string.IsNullOrEmpty(documentType.System)) + if (!StringUtils.IsNullOrEmpty(documentType.System)) { writer.WritePropertyName("@system"); writer.WriteValue(documentType.System); } - if (!string.IsNullOrEmpty(documentType.InternalSubset)) + if (!StringUtils.IsNullOrEmpty(documentType.InternalSubset)) { writer.WritePropertyName("@internalSubset"); writer.WriteValue(documentType.InternalSubset); @@ -1473,7 +1478,7 @@ private static bool AllSameName(IXmlNode node) /// The existing value of object being read. /// The calling serializer. /// The object value. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { switch (reader.TokenType) { @@ -1486,8 +1491,8 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable()); - IXmlDocument document = null; - IXmlNode rootNode = null; + IXmlDocument? document = null; + IXmlNode? rootNode = null; #if HAVE_XLINQ if (typeof(XObject).IsAssignableFrom(objectType)) @@ -1532,7 +1537,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw JsonSerializationException.Create(reader, "Unexpected type when converting XML: " + objectType); } - if (!string.IsNullOrEmpty(DeserializeRootElementName)) + if (!StringUtils.IsNullOrEmpty(DeserializeRootElementName)) { ReadElement(reader, document, rootNode, DeserializeRootElementName, manager); } @@ -1545,7 +1550,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_XLINQ if (objectType == typeof(XElement)) { - XElement element = (XElement)document.DocumentElement.WrappedNode; + XElement element = (XElement)document.DocumentElement!.WrappedNode!; element.Remove(); return element; @@ -1554,7 +1559,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist #if HAVE_XML_DOCUMENT if (objectType == typeof(XmlElement)) { - return document.DocumentElement.WrappedNode; + return document.DocumentElement!.WrappedNode; } #endif @@ -1581,7 +1586,7 @@ private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNames return; default: // processing instructions and the xml declaration start with ? - if (!string.IsNullOrEmpty(propertyName) && propertyName[0] == '?') + if (!StringUtils.IsNullOrEmpty(propertyName) && propertyName[0] == '?') { CreateInstruction(reader, document, currentNode, propertyName); return; @@ -1611,13 +1616,13 @@ private void DeserializeValue(JsonReader reader, IXmlDocument document, XmlNames private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, XmlNamespaceManager manager) { - if (string.IsNullOrEmpty(propertyName)) + if (StringUtils.IsNullOrEmpty(propertyName)) { throw JsonSerializationException.Create(reader, "XmlNodeConverter cannot convert JSON with an empty property name to XML."); } - Dictionary attributeNameValues = null; - string elementPrefix = null; + Dictionary? attributeNameValues = null; + string? elementPrefix = null; if (!EncodeSpecialCharacters) { @@ -1629,7 +1634,7 @@ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode curr if (propertyName.StartsWith('@')) { string attributeName = propertyName.Substring(1); - string attributePrefix = MiscellaneousUtils.GetPrefix(attributeName); + string? attributePrefix = MiscellaneousUtils.GetPrefix(attributeName); AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix); return; @@ -1649,7 +1654,7 @@ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode curr case JsonTypeReflector.TypePropertyName: case JsonTypeReflector.ValuePropertyName: string attributeName = propertyName.Substring(1); - string attributePrefix = manager.LookupPrefix(JsonNamespaceUri); + string? attributePrefix = manager.LookupPrefix(JsonNamespaceUri); AddAttribute(reader, document, currentNode, propertyName, attributeName, manager, attributePrefix); return; } @@ -1666,7 +1671,7 @@ private void ReadElement(JsonReader reader, IXmlDocument document, IXmlNode curr CreateElement(reader, document, currentNode, propertyName, manager, elementPrefix, attributeNameValues); } - private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string elementPrefix, Dictionary attributeNameValues) + private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string elementName, XmlNamespaceManager manager, string? elementPrefix, Dictionary? attributeNameValues) { IXmlElement element = CreateElement(elementName, document, elementPrefix, manager); @@ -1675,12 +1680,14 @@ private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode cu if (attributeNameValues != null) { // add attributes to newly created element - foreach (KeyValuePair nameValue in attributeNameValues) + foreach (KeyValuePair nameValue in attributeNameValues) { string encodedName = XmlConvert.EncodeName(nameValue.Key); - string attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key); + string? attributePrefix = MiscellaneousUtils.GetPrefix(nameValue.Key); - IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix)) ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix) ?? string.Empty, nameValue.Value) : document.CreateAttribute(encodedName, nameValue.Value); + IXmlNode attribute = (!StringUtils.IsNullOrEmpty(attributePrefix)) + ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix) ?? string.Empty, nameValue.Value!) + : document.CreateAttribute(encodedName, nameValue.Value!); element.SetAttributeNode(attribute); } @@ -1694,7 +1701,7 @@ private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode cu case JsonToken.Boolean: case JsonToken.Date: case JsonToken.Bytes: - string text = ConvertTokenToXmlValue(reader); + string? text = ConvertTokenToXmlValue(reader); if (text != null) { element.AppendChild(document.CreateTextNode(text)); @@ -1718,7 +1725,7 @@ private void CreateElement(JsonReader reader, IXmlDocument document, IXmlNode cu } } - private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, string attributeName, XmlNamespaceManager manager, string attributePrefix) + private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlNode currentNode, string propertyName, string attributeName, XmlNamespaceManager manager, string? attributePrefix) { if (currentNode.NodeType == XmlNodeType.Document) { @@ -1726,16 +1733,16 @@ private static void AddAttribute(JsonReader reader, IXmlDocument document, IXmlN } string encodedName = XmlConvert.EncodeName(attributeName); - string attributeValue = ConvertTokenToXmlValue(reader); + string attributeValue = ConvertTokenToXmlValue(reader)!; - IXmlNode attribute = (!string.IsNullOrEmpty(attributePrefix)) - ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix), attributeValue) + IXmlNode attribute = (!StringUtils.IsNullOrEmpty(attributePrefix)) + ? document.CreateAttribute(encodedName, manager.LookupNamespace(attributePrefix)!, attributeValue) : document.CreateAttribute(encodedName, attributeValue); ((IXmlElement)currentNode).SetAttributeNode(attribute); } - private static string ConvertTokenToXmlValue(JsonReader reader) + private static string? ConvertTokenToXmlValue(JsonReader reader) { switch (reader.TokenType) { @@ -1782,7 +1789,7 @@ private static string ConvertTokenToXmlValue(JsonReader reader) #endif } case JsonToken.Bytes: - return Convert.ToBase64String((byte[])reader.Value); + return Convert.ToBase64String((byte[])reader.Value!); case JsonToken.Null: return null; default: @@ -1792,7 +1799,7 @@ private static string ConvertTokenToXmlValue(JsonReader reader) private void ReadArrayElements(JsonReader reader, IXmlDocument document, string propertyName, IXmlNode currentNode, XmlNamespaceManager manager) { - string elementPrefix = MiscellaneousUtils.GetPrefix(propertyName); + string? elementPrefix = MiscellaneousUtils.GetPrefix(propertyName); IXmlElement nestedArrayElement = CreateElement(propertyName, document, elementPrefix, manager); @@ -1858,9 +1865,9 @@ private bool ShouldReadInto(JsonReader reader) return true; } - private Dictionary ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager) + private Dictionary? ReadAttributeElements(JsonReader reader, XmlNamespaceManager manager) { - Dictionary attributeNameValues = null; + Dictionary? attributeNameValues = null; bool finished = false; // read properties until first non-attribute is encountered @@ -1869,19 +1876,19 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN switch (reader.TokenType) { case JsonToken.PropertyName: - string attributeName = reader.Value.ToString(); + string attributeName = reader.Value!.ToString()!; - if (!string.IsNullOrEmpty(attributeName)) + if (!StringUtils.IsNullOrEmpty(attributeName)) { char firstChar = attributeName[0]; - string attributeValue; + string? attributeValue; switch (firstChar) { case '@': if (attributeNameValues == null) { - attributeNameValues = new Dictionary(); + attributeNameValues = new Dictionary(); } attributeName = attributeName.Substring(1); @@ -1889,9 +1896,9 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN attributeValue = ConvertTokenToXmlValue(reader); attributeNameValues.Add(attributeName, attributeValue); - if (IsNamespaceAttribute(attributeName, out string namespacePrefix)) + if (IsNamespaceAttribute(attributeName, out string? namespacePrefix)) { - manager.AddNamespace(namespacePrefix, attributeValue); + manager.AddNamespace(namespacePrefix, attributeValue!); } break; case '$': @@ -1904,12 +1911,12 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN case JsonTypeReflector.ValuePropertyName: // check that JsonNamespaceUri is in scope // if it isn't then add it to document and namespace manager - string jsonPrefix = manager.LookupPrefix(JsonNamespaceUri); + string? jsonPrefix = manager.LookupPrefix(JsonNamespaceUri); if (jsonPrefix == null) { if (attributeNameValues == null) { - attributeNameValues = new Dictionary(); + attributeNameValues = new Dictionary(); } // ensure that the prefix used is free @@ -1941,7 +1948,7 @@ private Dictionary ReadAttributeElements(JsonReader reader, XmlN if (attributeNameValues == null) { - attributeNameValues = new Dictionary(); + attributeNameValues = new Dictionary(); } attributeValue = reader.Value?.ToString(); @@ -1979,12 +1986,12 @@ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNod { if (propertyName == DeclarationName) { - string version = null; - string encoding = null; - string standalone = null; + string? version = null; + string? encoding = null; + string? standalone = null; while (reader.Read() && reader.TokenType != JsonToken.EndObject) { - switch (reader.Value.ToString()) + switch (reader.Value?.ToString()) { case "@version": reader.ReadAndAssert(); @@ -2003,12 +2010,17 @@ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNod } } + if (version == null) + { + throw JsonSerializationException.Create(reader, "Version not specified for XML declaration."); + } + IXmlNode declaration = document.CreateXmlDeclaration(version, encoding, standalone); currentNode.AppendChild(declaration); } else { - IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), ConvertTokenToXmlValue(reader)); + IXmlNode instruction = document.CreateProcessingInstruction(propertyName.Substring(1), ConvertTokenToXmlValue(reader)!); currentNode.AppendChild(instruction); } } @@ -2016,13 +2028,13 @@ private void CreateInstruction(JsonReader reader, IXmlDocument document, IXmlNod #if HAVE_XML_DOCUMENT_TYPE private void CreateDocumentType(JsonReader reader, IXmlDocument document, IXmlNode currentNode) { - string name = null; - string publicId = null; - string systemId = null; - string internalSubset = null; + string? name = null; + string? publicId = null; + string? systemId = null; + string? internalSubset = null; while (reader.Read() && reader.TokenType != JsonToken.EndObject) { - switch (reader.Value.ToString()) + switch (reader.Value?.ToString()) { case "@name": reader.ReadAndAssert(); @@ -2045,17 +2057,22 @@ private void CreateDocumentType(JsonReader reader, IXmlDocument document, IXmlNo } } + if (name == null) + { + throw JsonSerializationException.Create(reader, "Name not specified for XML document type."); + } + IXmlNode documentType = document.CreateXmlDocumentType(name, publicId, systemId, internalSubset); currentNode.AppendChild(documentType); } #endif - private IXmlElement CreateElement(string elementName, IXmlDocument document, string elementPrefix, XmlNamespaceManager manager) + private IXmlElement CreateElement(string elementName, IXmlDocument document, string? elementPrefix, XmlNamespaceManager manager) { string encodeName = EncodeSpecialCharacters ? XmlConvert.EncodeLocalName(elementName) : XmlConvert.EncodeName(elementName); - string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); + string? ns = StringUtils.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); - IXmlElement element = (!string.IsNullOrEmpty(ns)) ? document.CreateElement(encodeName, ns) : document.CreateElement(encodeName); + IXmlElement element = (!StringUtils.IsNullOrEmpty(ns)) ? document.CreateElement(encodeName, ns) : document.CreateElement(encodeName); return element; } @@ -2072,7 +2089,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp throw JsonSerializationException.Create(reader, "JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifying a DeserializeRootElementName."); } - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; reader.ReadAndAssert(); if (reader.TokenType == JsonToken.StartArray) @@ -2086,8 +2103,8 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp if (count == 1 && WriteArrayAttribute) { - MiscellaneousUtils.GetQualifiedNameParts(propertyName, out string elementPrefix, out string localName); - string ns = string.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); + MiscellaneousUtils.GetQualifiedNameParts(propertyName, out string? elementPrefix, out string localName); + string? ns = StringUtils.IsNullOrEmpty(elementPrefix) ? manager.DefaultNamespace : manager.LookupNamespace(elementPrefix); foreach (IXmlNode childNode in currentNode.ChildNodes) { @@ -2105,7 +2122,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp } continue; case JsonToken.StartConstructor: - string constructorName = reader.Value.ToString(); + string constructorName = reader.Value!.ToString()!; while (reader.Read() && reader.TokenType != JsonToken.EndConstructor) { @@ -2113,7 +2130,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp } break; case JsonToken.Comment: - currentNode.AppendChild(document.CreateComment((string)reader.Value)); + currentNode.AppendChild(document.CreateComment((string)reader.Value!)); break; case JsonToken.EndObject: case JsonToken.EndArray: @@ -2131,7 +2148,7 @@ private void DeserializeNode(JsonReader reader, IXmlDocument document, XmlNamesp /// Attribute name to test. /// The attribute name prefix if it has one, otherwise an empty string. /// true if attribute name is for a namespace attribute, otherwise false. - private bool IsNamespaceAttribute(string attributeName, out string prefix) + private bool IsNamespaceAttribute(string attributeName, [NotNullWhen(true)]out string? prefix) { if (attributeName.StartsWith("xmlns", StringComparison.Ordinal)) { diff --git a/Src/Newtonsoft.Json/DateParseHandling.cs b/Src/Newtonsoft.Json/DateParseHandling.cs index 481098c82..7fc8a46e3 100644 --- a/Src/Newtonsoft.Json/DateParseHandling.cs +++ b/Src/Newtonsoft.Json/DateParseHandling.cs @@ -36,14 +36,14 @@ public enum DateParseHandling None = 0, /// - /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . + /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . /// DateTime = 1, #if HAVE_DATE_TIME_OFFSET /// - /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . + /// Date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed to . /// DateTimeOffset = 2 #endif } -} \ No newline at end of file +} diff --git a/Src/Newtonsoft.Json/DefaultJsonNameTable.cs b/Src/Newtonsoft.Json/DefaultJsonNameTable.cs index 8b6db5522..659eefab7 100644 --- a/Src/Newtonsoft.Json/DefaultJsonNameTable.cs +++ b/Src/Newtonsoft.Json/DefaultJsonNameTable.cs @@ -24,6 +24,7 @@ #endregion using System; +using System.Threading; namespace Newtonsoft.Json { @@ -59,7 +60,7 @@ public DefaultJsonNameTable() /// The zero-based index into the array specifying the first character of the name. /// The number of characters in the name. /// A string containing the same characters as the specified range of characters in the given array. - public override string Get(char[] key, int start, int length) + public override string? Get(char[] key, int start, int length) { if (length == 0) { @@ -78,7 +79,12 @@ public override string Get(char[] key, int start, int length) hashCode -= hashCode >> 5; // make sure index is evaluated before accessing _entries, otherwise potential race condition causing IndexOutOfRangeException - var index = hashCode & _mask; +#if NET20 || NET35 || NET40 + int mask = Thread.VolatileRead(ref _mask); +#else + int mask = Volatile.Read(ref _mask); +#endif + var index = hashCode & mask; var entries = _entries; for (Entry entry = entries[index]; entry != null; entry = entry.Next) @@ -160,7 +166,12 @@ private void Grow() } } _entries = newEntries; - _mask = newMask; + +#if NET20 || NET35 || NET40 + Thread.VolatileWrite(ref _mask, newMask); +#else + Volatile.Write(ref _mask, newMask); +#endif } private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length) diff --git a/Src/Newtonsoft.Json/IArrayPool.cs b/Src/Newtonsoft.Json/IArrayPool.cs index 15717f05a..361ee890b 100644 --- a/Src/Newtonsoft.Json/IArrayPool.cs +++ b/Src/Newtonsoft.Json/IArrayPool.cs @@ -17,6 +17,6 @@ public interface IArrayPool /// Return an array to the pool. /// /// The array that is being returned. - void Return(T[] array); + void Return(T[]? array); } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonContainerAttribute.cs b/Src/Newtonsoft.Json/JsonContainerAttribute.cs index e5ef292d3..28f35f531 100644 --- a/Src/Newtonsoft.Json/JsonContainerAttribute.cs +++ b/Src/Newtonsoft.Json/JsonContainerAttribute.cs @@ -38,25 +38,25 @@ public abstract class JsonContainerAttribute : Attribute /// Gets or sets the id. /// /// The id. - public string Id { get; set; } + public string? Id { get; set; } /// /// Gets or sets the title. /// /// The title. - public string Title { get; set; } + public string? Title { get; set; } /// /// Gets or sets the description. /// /// The description. - public string Description { get; set; } + public string? Description { get; set; } /// /// Gets or sets the collection's items converter. /// /// The collection's items converter. - public Type ItemConverterType { get; set; } + public Type? ItemConverterType { get; set; } /// /// The parameter list to use when constructing the described by . @@ -69,13 +69,13 @@ public abstract class JsonContainerAttribute : Attribute /// [JsonContainer(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })] /// /// - public object[] ItemConverterParameters { get; set; } + public object[]? ItemConverterParameters { get; set; } /// /// Gets or sets the of the . /// /// The of the . - public Type NamingStrategyType + public Type? NamingStrategyType { get => _namingStrategyType; set @@ -96,7 +96,7 @@ public Type NamingStrategyType /// [JsonContainer(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })] /// /// - public object[] NamingStrategyParameters + public object[]? NamingStrategyParameters { get => _namingStrategyParameters; set @@ -106,7 +106,7 @@ public object[] NamingStrategyParameters } } - internal NamingStrategy NamingStrategyInstance { get; set; } + internal NamingStrategy? NamingStrategyInstance { get; set; } // yuck. can't set nullable properties on an attribute in C# // have to use this approach to get an unset default state @@ -114,8 +114,8 @@ public object[] NamingStrategyParameters internal bool? _itemIsReference; internal ReferenceLoopHandling? _itemReferenceLoopHandling; internal TypeNameHandling? _itemTypeNameHandling; - private Type _namingStrategyType; - private object[] _namingStrategyParameters; + private Type? _namingStrategyType; + private object[]? _namingStrategyParameters; /// /// Gets or sets a value that indicates whether to preserve object references. diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index b0e480d62..95019e2b7 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -36,9 +36,10 @@ using Newtonsoft.Json.Serialization; using System.Text; using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if HAVE_XLINQ using System.Xml.Linq; - #endif namespace Newtonsoft.Json @@ -58,7 +59,7 @@ public static class JsonConvert /// To serialize without using any default settings create a with /// . /// - public static Func DefaultSettings { get; set; } + public static Func? DefaultSettings { get; set; } /// /// Represents JavaScript's boolean value true as a string. This field is read-only. @@ -301,7 +302,7 @@ internal static string ToString(double value, FloatFormatHandling floatFormatHan private static string EnsureDecimalPlace(double value, string text) { - if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1 || text.IndexOf('e') != -1) + if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1) { return text; } @@ -311,7 +312,7 @@ private static string EnsureDecimalPlace(double value, string text) private static string EnsureDecimalPlace(string text) { - if (text.IndexOf('.') != -1) + if (StringUtils.IndexOf(text, '.') != -1) { return text; } @@ -395,7 +396,7 @@ internal static string ToString(TimeSpan value, char quoteChar) /// /// The value to convert. /// A JSON string representation of the . - public static string ToString(Uri value) + public static string ToString(Uri? value) { if (value == null) { @@ -415,7 +416,7 @@ internal static string ToString(Uri value, char quoteChar) /// /// The value to convert. /// A JSON string representation of the . - public static string ToString(string value) + public static string ToString(string? value) { return ToString(value, '"'); } @@ -426,7 +427,7 @@ public static string ToString(string value) /// The value to convert. /// The string delimiter character. /// A JSON string representation of the . - public static string ToString(string value, char delimiter) + public static string ToString(string? value, char delimiter) { return ToString(value, delimiter, StringEscapeHandling.Default); } @@ -438,7 +439,7 @@ public static string ToString(string value, char delimiter) /// The string delimiter character. /// The string escape handling. /// A JSON string representation of the . - public static string ToString(string value, char delimiter, StringEscapeHandling stringEscapeHandling) + public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling) { if (delimiter != '"' && delimiter != '\'') { @@ -453,7 +454,7 @@ public static string ToString(string value, char delimiter, StringEscapeHandling /// /// The value to convert. /// A JSON string representation of the . - public static string ToString(object value) + public static string ToString(object? value) { if (value == null) { @@ -524,9 +525,9 @@ public static string ToString(object value) /// The object to serialize. /// A JSON string representation of the object. [DebuggerStepThrough] - public static string SerializeObject(object value) + public static string SerializeObject(object? value) { - return SerializeObject(value, null, (JsonSerializerSettings)null); + return SerializeObject(value, null, (JsonSerializerSettings?)null); } /// @@ -538,9 +539,9 @@ public static string SerializeObject(object value) /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Formatting formatting) + public static string SerializeObject(object? value, Formatting formatting) { - return SerializeObject(value, formatting, (JsonSerializerSettings)null); + return SerializeObject(value, formatting, (JsonSerializerSettings?)null); } /// @@ -550,9 +551,9 @@ public static string SerializeObject(object value, Formatting formatting) /// A collection of converters used while serializing. /// A JSON string representation of the object. [DebuggerStepThrough] - public static string SerializeObject(object value, params JsonConverter[] converters) + public static string SerializeObject(object? value, params JsonConverter[] converters) { - JsonSerializerSettings settings = (converters != null && converters.Length > 0) + JsonSerializerSettings? settings = (converters != null && converters.Length > 0) ? new JsonSerializerSettings { Converters = converters } : null; @@ -567,9 +568,9 @@ public static string SerializeObject(object value, params JsonConverter[] conver /// A collection of converters used while serializing. /// A JSON string representation of the object. [DebuggerStepThrough] - public static string SerializeObject(object value, Formatting formatting, params JsonConverter[] converters) + public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters) { - JsonSerializerSettings settings = (converters != null && converters.Length > 0) + JsonSerializerSettings? settings = (converters != null && converters.Length > 0) ? new JsonSerializerSettings { Converters = converters } : null; @@ -586,7 +587,7 @@ public static string SerializeObject(object value, Formatting formatting, params /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, JsonSerializerSettings settings) + public static string SerializeObject(object? value, JsonSerializerSettings? settings) { return SerializeObject(value, null, settings); } @@ -606,7 +607,7 @@ public static string SerializeObject(object value, JsonSerializerSettings settin /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Type type, JsonSerializerSettings settings) + public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); @@ -624,7 +625,7 @@ public static string SerializeObject(object value, Type type, JsonSerializerSett /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Formatting formatting, JsonSerializerSettings settings) + public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings) { return SerializeObject(value, null, formatting, settings); } @@ -645,7 +646,7 @@ public static string SerializeObject(object value, Formatting formatting, JsonSe /// A JSON string representation of the object. /// [DebuggerStepThrough] - public static string SerializeObject(object value, Type type, Formatting formatting, JsonSerializerSettings settings) + public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); jsonSerializer.Formatting = formatting; @@ -653,7 +654,7 @@ public static string SerializeObject(object value, Type type, Formatting formatt return SerializeObjectInternal(value, type, jsonSerializer); } - private static string SerializeObjectInternal(object value, Type type, JsonSerializer jsonSerializer) + private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer) { StringBuilder sb = new StringBuilder(256); StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture); @@ -675,9 +676,9 @@ private static string SerializeObjectInternal(object value, Type type, JsonSeria /// The JSON to deserialize. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value) + public static object? DeserializeObject(string value) { - return DeserializeObject(value, null, (JsonSerializerSettings)null); + return DeserializeObject(value, null, (JsonSerializerSettings?)null); } /// @@ -690,7 +691,7 @@ public static object DeserializeObject(string value) /// /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value, JsonSerializerSettings settings) + public static object? DeserializeObject(string value, JsonSerializerSettings settings) { return DeserializeObject(value, null, settings); } @@ -702,9 +703,9 @@ public static object DeserializeObject(string value, JsonSerializerSettings sett /// The of object being deserialized. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value, Type type) + public static object? DeserializeObject(string value, Type type) { - return DeserializeObject(value, type, (JsonSerializerSettings)null); + return DeserializeObject(value, type, (JsonSerializerSettings?)null); } /// @@ -714,9 +715,9 @@ public static object DeserializeObject(string value, Type type) /// The JSON to deserialize. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static T DeserializeObject(string value) + public static T? DeserializeObject(string value) { - return DeserializeObject(value, (JsonSerializerSettings)null); + return DeserializeObject(value, (JsonSerializerSettings?)null); } /// @@ -731,7 +732,7 @@ public static T DeserializeObject(string value) /// The anonymous type object. /// The deserialized anonymous type from the JSON string. [DebuggerStepThrough] - public static T DeserializeAnonymousType(string value, T anonymousTypeObject) + public static T? DeserializeAnonymousType(string value, T anonymousTypeObject) { return DeserializeObject(value); } @@ -752,7 +753,7 @@ public static T DeserializeAnonymousType(string value, T anonymousTypeObject) /// /// The deserialized anonymous type from the JSON string. [DebuggerStepThrough] - public static T DeserializeAnonymousType(string value, T anonymousTypeObject, JsonSerializerSettings settings) + public static T? DeserializeAnonymousType(string value, T anonymousTypeObject, JsonSerializerSettings settings) { return DeserializeObject(value, settings); } @@ -765,9 +766,9 @@ public static T DeserializeAnonymousType(string value, T anonymousTypeObject, /// Converters to use while deserializing. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static T DeserializeObject(string value, params JsonConverter[] converters) + public static T? DeserializeObject(string value, params JsonConverter[] converters) { - return (T)DeserializeObject(value, typeof(T), converters); + return (T?)DeserializeObject(value, typeof(T), converters); } /// @@ -781,9 +782,9 @@ public static T DeserializeObject(string value, params JsonConverter[] conver /// /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static T DeserializeObject(string value, JsonSerializerSettings settings) + public static T? DeserializeObject(string value, JsonSerializerSettings? settings) { - return (T)DeserializeObject(value, typeof(T), settings); + return (T?)DeserializeObject(value, typeof(T), settings); } /// @@ -794,9 +795,9 @@ public static T DeserializeObject(string value, JsonSerializerSettings settin /// Converters to use while deserializing. /// The deserialized object from the JSON string. [DebuggerStepThrough] - public static object DeserializeObject(string value, Type type, params JsonConverter[] converters) + public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters) { - JsonSerializerSettings settings = (converters != null && converters.Length > 0) + JsonSerializerSettings? settings = (converters != null && converters.Length > 0) ? new JsonSerializerSettings { Converters = converters } : null; @@ -813,7 +814,7 @@ public static object DeserializeObject(string value, Type type, params JsonConve /// If this is null, default serialization settings will be used. /// /// The deserialized object from the JSON string. - public static object DeserializeObject(string value, Type type, JsonSerializerSettings settings) + public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings) { ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -853,7 +854,7 @@ public static void PopulateObject(string value, object target) /// The used to deserialize the object. /// If this is null, default serialization settings will be used. /// - public static void PopulateObject(string value, object target, JsonSerializerSettings settings) + public static void PopulateObject(string value, object target, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); @@ -882,7 +883,7 @@ public static void PopulateObject(string value, object target, JsonSerializerSet /// /// The node to serialize. /// A JSON string of the . - public static string SerializeXmlNode(XmlNode node) + public static string SerializeXmlNode(XmlNode? node) { return SerializeXmlNode(node, Formatting.None); } @@ -893,7 +894,7 @@ public static string SerializeXmlNode(XmlNode node) /// The node to serialize. /// Indicates how the output should be formatted. /// A JSON string of the . - public static string SerializeXmlNode(XmlNode node, Formatting formatting) + public static string SerializeXmlNode(XmlNode? node, Formatting formatting) { XmlNodeConverter converter = new XmlNodeConverter(); @@ -907,7 +908,7 @@ public static string SerializeXmlNode(XmlNode node, Formatting formatting) /// Indicates how the output should be formatted. /// Omits writing the root object. /// A JSON string of the . - public static string SerializeXmlNode(XmlNode node, Formatting formatting, bool omitRootObject) + public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject) { XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject }; @@ -919,7 +920,7 @@ public static string SerializeXmlNode(XmlNode node, Formatting formatting, bool /// /// The JSON string. /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value) + public static XmlDocument? DeserializeXmlNode(string value) { return DeserializeXmlNode(value, null); } @@ -930,7 +931,7 @@ public static XmlDocument DeserializeXmlNode(string value) /// The JSON string. /// The name of the root element to append when deserializing. /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName) + public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName) { return DeserializeXmlNode(value, deserializeRootElementName, false); } @@ -946,7 +947,7 @@ public static XmlDocument DeserializeXmlNode(string value, string deserializeRoo /// This attribute helps preserve arrays when converting the written XML back to JSON. /// /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName, bool writeArrayAttribute) + public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute) { return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, false); } @@ -968,14 +969,14 @@ public static XmlDocument DeserializeXmlNode(string value, string deserializeRoo /// as part of the XML element name. /// /// The deserialized . - public static XmlDocument DeserializeXmlNode(string value, string deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) + public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) { XmlNodeConverter converter = new XmlNodeConverter(); converter.DeserializeRootElementName = deserializeRootElementName; converter.WriteArrayAttribute = writeArrayAttribute; converter.EncodeSpecialCharacters = encodeSpecialCharacters; - return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), converter); + return (XmlDocument?)DeserializeObject(value, typeof(XmlDocument), converter); } #endif @@ -985,7 +986,7 @@ public static XmlDocument DeserializeXmlNode(string value, string deserializeRoo /// /// The node to convert to JSON. /// A JSON string of the . - public static string SerializeXNode(XObject node) + public static string SerializeXNode(XObject? node) { return SerializeXNode(node, Formatting.None); } @@ -996,7 +997,7 @@ public static string SerializeXNode(XObject node) /// The node to convert to JSON. /// Indicates how the output should be formatted. /// A JSON string of the . - public static string SerializeXNode(XObject node, Formatting formatting) + public static string SerializeXNode(XObject? node, Formatting formatting) { return SerializeXNode(node, formatting, false); } @@ -1008,7 +1009,7 @@ public static string SerializeXNode(XObject node, Formatting formatting) /// Indicates how the output should be formatted. /// Omits writing the root object. /// A JSON string of the . - public static string SerializeXNode(XObject node, Formatting formatting, bool omitRootObject) + public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject) { XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject }; @@ -1020,7 +1021,7 @@ public static string SerializeXNode(XObject node, Formatting formatting, bool om /// /// The JSON string. /// The deserialized . - public static XDocument DeserializeXNode(string value) + public static XDocument? DeserializeXNode(string value) { return DeserializeXNode(value, null); } @@ -1031,7 +1032,7 @@ public static XDocument DeserializeXNode(string value) /// The JSON string. /// The name of the root element to append when deserializing. /// The deserialized . - public static XDocument DeserializeXNode(string value, string deserializeRootElementName) + public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName) { return DeserializeXNode(value, deserializeRootElementName, false); } @@ -1047,7 +1048,7 @@ public static XDocument DeserializeXNode(string value, string deserializeRootEle /// This attribute helps preserve arrays when converting the written XML back to JSON. /// /// The deserialized . - public static XDocument DeserializeXNode(string value, string deserializeRootElementName, bool writeArrayAttribute) + public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute) { return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, false); } @@ -1069,14 +1070,14 @@ public static XDocument DeserializeXNode(string value, string deserializeRootEle /// as part of the XML element name. /// /// The deserialized . - public static XDocument DeserializeXNode(string value, string deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) + public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) { XmlNodeConverter converter = new XmlNodeConverter(); converter.DeserializeRootElementName = deserializeRootElementName; converter.WriteArrayAttribute = writeArrayAttribute; converter.EncodeSpecialCharacters = encodeSpecialCharacters; - return (XDocument)DeserializeObject(value, typeof(XDocument), converter); + return (XDocument?)DeserializeObject(value, typeof(XDocument), converter); } #endif #endregion diff --git a/Src/Newtonsoft.Json/JsonConverter.cs b/Src/Newtonsoft.Json/JsonConverter.cs index 2ac14e50f..2c04a09d9 100644 --- a/Src/Newtonsoft.Json/JsonConverter.cs +++ b/Src/Newtonsoft.Json/JsonConverter.cs @@ -26,6 +26,8 @@ using System; using Newtonsoft.Json.Utilities; using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Newtonsoft.Json { @@ -40,7 +42,7 @@ public abstract class JsonConverter /// The to write to. /// The value. /// The calling serializer. - public abstract void WriteJson(JsonWriter writer, object value, JsonSerializer serializer); + public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer); /// /// Reads the JSON representation of the object. @@ -50,7 +52,7 @@ public abstract class JsonConverter /// The existing value of object being read. /// The calling serializer. /// The object value. - public abstract object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer); + public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer); /// /// Determines whether this instance can convert the specified object type. @@ -86,13 +88,13 @@ public abstract class JsonConverter : JsonConverter /// The to write to. /// The value. /// The calling serializer. - public sealed override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (!(value != null ? value is T : ReflectionUtils.IsNullable(typeof(T)))) { throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } - WriteJson(writer, (T)value, serializer); + WriteJson(writer, (T?)value, serializer); } /// @@ -101,7 +103,7 @@ public sealed override void WriteJson(JsonWriter writer, object value, JsonSeria /// The to write to. /// The value. /// The calling serializer. - public abstract void WriteJson(JsonWriter writer, T value, JsonSerializer serializer); + public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer); /// /// Reads the JSON representation of the object. @@ -111,14 +113,14 @@ public sealed override void WriteJson(JsonWriter writer, object value, JsonSeria /// The existing value of object being read. /// The calling serializer. /// The object value. - public sealed override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { bool existingIsNull = existingValue == null; if (!(existingIsNull || existingValue is T)) { throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } - return ReadJson(reader, objectType, existingIsNull ? default : (T)existingValue, !existingIsNull, serializer); + return ReadJson(reader, objectType, existingIsNull ? default : (T?)existingValue, !existingIsNull, serializer); } /// @@ -130,7 +132,7 @@ public sealed override object ReadJson(JsonReader reader, Type objectType, objec /// The existing value has a value. /// The calling serializer. /// The object value. - public abstract T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer); + public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer); /// /// Determines whether this instance can convert the specified object type. diff --git a/Src/Newtonsoft.Json/JsonConverterAttribute.cs b/Src/Newtonsoft.Json/JsonConverterAttribute.cs index 2c09128c1..a5f071ea7 100644 --- a/Src/Newtonsoft.Json/JsonConverterAttribute.cs +++ b/Src/Newtonsoft.Json/JsonConverterAttribute.cs @@ -47,7 +47,7 @@ public sealed class JsonConverterAttribute : Attribute /// The parameter list to use when constructing the described by . /// If null, the default constructor is used. /// - public object[] ConverterParameters { get; } + public object[]? ConverterParameters { get; } /// /// Initializes a new instance of the class. diff --git a/Src/Newtonsoft.Json/JsonException.cs b/Src/Newtonsoft.Json/JsonException.cs index a5fb5775a..603a78162 100644 --- a/Src/Newtonsoft.Json/JsonException.cs +++ b/Src/Newtonsoft.Json/JsonException.cs @@ -63,7 +63,7 @@ public JsonException(string message) /// /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonException(string message, Exception innerException) + public JsonException(string message, Exception? innerException) : base(message, innerException) { } diff --git a/Src/Newtonsoft.Json/JsonNameTable.cs b/Src/Newtonsoft.Json/JsonNameTable.cs index b7937618a..1f2d243a6 100644 --- a/Src/Newtonsoft.Json/JsonNameTable.cs +++ b/Src/Newtonsoft.Json/JsonNameTable.cs @@ -12,6 +12,6 @@ public abstract class JsonNameTable /// The zero-based index into the array specifying the first character of the name. /// The number of characters in the name. /// A string containing the same characters as the specified range of characters in the given array. - public abstract string Get(char[] key, int start, int length); + public abstract string? Get(char[] key, int start, int length); } } diff --git a/Src/Newtonsoft.Json/JsonPosition.cs b/Src/Newtonsoft.Json/JsonPosition.cs index b301993ea..92a62344d 100644 --- a/Src/Newtonsoft.Json/JsonPosition.cs +++ b/Src/Newtonsoft.Json/JsonPosition.cs @@ -46,7 +46,7 @@ internal struct JsonPosition internal JsonContainerType Type; internal int Position; - internal string PropertyName; + internal string? PropertyName; internal bool HasIndex; public JsonPosition(JsonContainerType type) @@ -62,7 +62,7 @@ internal int CalculateLength() switch (Type) { case JsonContainerType.Object: - return PropertyName.Length + 5; + return PropertyName!.Length + 5; case JsonContainerType.Array: case JsonContainerType.Constructor: return MathUtils.IntLength((ulong)Position) + 2; @@ -71,12 +71,12 @@ internal int CalculateLength() } } - internal void WriteTo(StringBuilder sb, ref StringWriter writer, ref char[] buffer) + internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer) { switch (Type) { case JsonContainerType.Object: - string propertyName = PropertyName; + string propertyName = PropertyName!; if (propertyName.IndexOfAny(SpecialCharacters) != -1) { sb.Append(@"['"); @@ -130,8 +130,8 @@ internal static string BuildPath(List positions, JsonPosition? cur } StringBuilder sb = new StringBuilder(capacity); - StringWriter writer = null; - char[] buffer = null; + StringWriter? writer = null; + char[]? buffer = null; if (positions != null) { foreach (JsonPosition state in positions) @@ -147,7 +147,7 @@ internal static string BuildPath(List positions, JsonPosition? cur return sb.ToString(); } - internal static string FormatMessage(IJsonLineInfo lineInfo, string path, string message) + internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message) { // don't add a fullstop and space when message ends with a new line if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal)) diff --git a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs index ec6532faf..7ad05382e 100644 --- a/Src/Newtonsoft.Json/JsonPropertyAttribute.cs +++ b/Src/Newtonsoft.Json/JsonPropertyAttribute.cs @@ -52,7 +52,7 @@ public sealed class JsonPropertyAttribute : Attribute /// Gets or sets the type used when serializing the property's collection items. /// /// The collection's items type. - public Type ItemConverterType { get; set; } + public Type? ItemConverterType { get; set; } /// /// The parameter list to use when constructing the described by . @@ -65,13 +65,13 @@ public sealed class JsonPropertyAttribute : Attribute /// [JsonProperty(ItemConverterType = typeof(MyContainerConverter), ItemConverterParameters = new object[] { 123, "Four" })] /// /// - public object[] ItemConverterParameters { get; set; } + public object[]? ItemConverterParameters { get; set; } /// /// Gets or sets the of the . /// /// The of the . - public Type NamingStrategyType { get; set; } + public Type? NamingStrategyType { get; set; } /// /// The parameter list to use when constructing the described by . @@ -84,7 +84,7 @@ public sealed class JsonPropertyAttribute : Attribute /// [JsonProperty(NamingStrategyType = typeof(MyNamingStrategy), NamingStrategyParameters = new object[] { 123, "Four" })] /// /// - public object[] NamingStrategyParameters { get; set; } + public object[]? NamingStrategyParameters { get; set; } /// /// Gets or sets the null value handling used when serializing this property. @@ -172,7 +172,7 @@ public Required Required /// Gets or sets the name of the property. /// /// The name of the property. - public string PropertyName { get; set; } + public string? PropertyName { get; set; } /// /// Gets or sets the reference loop handling used when serializing the property's collection items. diff --git a/Src/Newtonsoft.Json/JsonReader.Async.cs b/Src/Newtonsoft.Json/JsonReader.Async.cs index e61e933ae..d76c492e5 100644 --- a/Src/Newtonsoft.Json/JsonReader.Async.cs +++ b/Src/Newtonsoft.Json/JsonReader.Async.cs @@ -34,7 +34,25 @@ namespace Newtonsoft.Json { public abstract partial class JsonReader +#if HAVE_ASYNC_DISPOSABLE + : IAsyncDisposable +#endif { +#if HAVE_ASYNC_DISPOSABLE + ValueTask IAsyncDisposable.DisposeAsync() + { + try + { + Dispose(true); + return default; + } + catch (Exception exc) + { + return ValueTask.FromException(exc); + } + } +#endif + /// /// Asynchronously reads the next JSON token from the source. /// @@ -101,12 +119,12 @@ internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken /// property returns the []. This result will be null at the end of an array. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task ReadAsBytesAsync(CancellationToken cancellationToken = default) + public virtual Task ReadAsBytesAsync(CancellationToken cancellationToken = default) { - return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsBytes()); + return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsBytes()); } - internal async Task ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken) + internal async Task ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken) { List buffer = new List(); @@ -199,9 +217,9 @@ internal async Task ReadArrayIntoByteArrayAsync(CancellationToken cancel /// property returns the . This result will be null at the end of an array. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task ReadAsStringAsync(CancellationToken cancellationToken = default) + public virtual Task ReadAsStringAsync(CancellationToken cancellationToken = default) { - return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsString()); + return cancellationToken.CancelIfRequestedAsync() ?? Task.FromResult(ReadAsString()); } internal async Task ReadAndMoveToContentAsync(CancellationToken cancellationToken) diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index f827c278c..e368afc15 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -113,18 +113,18 @@ protected internal enum State // current Token data private JsonToken _tokenType; - private object _value; + private object? _value; internal char _quoteChar; internal State _currentState; private JsonPosition _currentPosition; - private CultureInfo _culture; + private CultureInfo? _culture; private DateTimeZoneHandling _dateTimeZoneHandling; private int? _maxDepth; private bool _hasExceededMaxDepth; internal DateParseHandling _dateParseHandling; internal FloatParseHandling _floatParseHandling; - private string _dateFormatString; - private List _stack; + private string? _dateFormatString; + private List? _stack; /// /// Gets the current reader state. @@ -219,7 +219,7 @@ public FloatParseHandling FloatParseHandling /// /// Gets or sets how custom date formatted strings are parsed when reading JSON. /// - public string DateFormatString + public string? DateFormatString { get => _dateFormatString; set => _dateFormatString = value; @@ -227,6 +227,8 @@ public string DateFormatString /// /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a . + /// A null value means there is no maximum. + /// The default value is 64. /// public int? MaxDepth { @@ -250,12 +252,12 @@ public int? MaxDepth /// /// Gets the text value of the current JSON token. /// - public virtual object Value => _value; + public virtual object? Value => _value; /// /// Gets the .NET type for the current JSON token. /// - public virtual Type ValueType => _value?.GetType(); + public virtual Type? ValueType => _value?.GetType(); /// /// Gets the depth of the current token in the JSON document. @@ -295,7 +297,7 @@ public virtual string Path JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null; - return JsonPosition.BuildPath(_stack, current); + return JsonPosition.BuildPath(_stack!, current); } } @@ -327,6 +329,7 @@ protected JsonReader() _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; _dateParseHandling = DateParseHandling.DateTime; _floatParseHandling = FloatParseHandling.Double; + _maxDepth = 64; CloseInput = true; } @@ -408,7 +411,7 @@ private JsonContainerType Peek() return null; case JsonToken.Integer: case JsonToken.Float: - object v = Value; + object v = Value!; if (v is int i) { return i; @@ -436,16 +439,16 @@ private JsonContainerType Peek() SetToken(JsonToken.Integer, i, false); return i; case JsonToken.String: - string s = (string)Value; + string? s = (string?)Value; return ReadInt32String(s); } throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal int? ReadInt32String(string s) + internal int? ReadInt32String(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -467,7 +470,7 @@ private JsonContainerType Peek() /// Reads the next JSON token from the source as a . /// /// A . This method will return null at the end of an array. - public virtual string ReadAsString() + public virtual string? ReadAsString() { JsonToken t = GetContentToken(); @@ -478,12 +481,12 @@ public virtual string ReadAsString() case JsonToken.EndArray: return null; case JsonToken.String: - return (string)Value; + return (string?)Value; } if (JsonTokenUtils.IsPrimitiveToken(t)) { - object v = Value; + object? v = Value; if (v != null) { string s; @@ -493,7 +496,7 @@ public virtual string ReadAsString() } else { - s = v is Uri uri ? uri.OriginalString : v.ToString(); + s = v is Uri uri ? uri.OriginalString : v.ToString()!; } SetToken(JsonToken.String, s, false); @@ -508,7 +511,7 @@ public virtual string ReadAsString() /// Reads the next JSON token from the source as a []. /// /// A [] or null if the next JSON token is null. This method will return null at the end of an array. - public virtual byte[] ReadAsBytes() + public virtual byte[]? ReadAsBytes() { JsonToken t = GetContentToken(); @@ -518,7 +521,7 @@ public virtual byte[] ReadAsBytes() { ReadIntoWrappedTypeObject(); - byte[] data = ReadAsBytes(); + byte[]? data = ReadAsBytes(); ReaderReadAndAssert(); if (TokenType != JsonToken.EndObject) @@ -533,7 +536,7 @@ public virtual byte[] ReadAsBytes() { // attempt to convert possible base 64 or GUID string to bytes // GUID has to have format 00000000-0000-0000-0000-000000000000 - string s = (string)Value; + string s = (string)Value!; byte[] data; @@ -565,7 +568,7 @@ public virtual byte[] ReadAsBytes() return data; } - return (byte[])Value; + return (byte[]?)Value; case JsonToken.StartArray: return ReadArrayIntoByteArray(); } @@ -627,7 +630,7 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) return null; case JsonToken.Integer: case JsonToken.Float: - object v = Value; + object v = Value!; if (v is double d) { return d; @@ -648,15 +651,15 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) return (double)d; case JsonToken.String: - return ReadDoubleString((string)Value); + return ReadDoubleString((string?)Value); } throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal double? ReadDoubleString(string s) + internal double? ReadDoubleString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -705,17 +708,17 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) SetToken(JsonToken.Boolean, b, false); return b; case JsonToken.String: - return ReadBooleanString((string)Value); + return ReadBooleanString((string?)Value); case JsonToken.Boolean: - return (bool)Value; + return (bool)Value!; } throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal bool? ReadBooleanString(string s) + internal bool? ReadBooleanString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -749,7 +752,7 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) return null; case JsonToken.Integer: case JsonToken.Float: - object v = Value; + object v = Value!; if (v is decimal d) { @@ -778,15 +781,15 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) SetToken(JsonToken.Float, d, false); return d; case JsonToken.String: - return ReadDecimalString((string)Value); + return ReadDecimalString((string?)Value); } throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } - internal decimal? ReadDecimalString(string s) + internal decimal? ReadDecimalString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -830,18 +833,17 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) } #endif - return (DateTime)Value; + return (DateTime)Value!; case JsonToken.String: - string s = (string)Value; - return ReadDateTimeString(s); + return ReadDateTimeString((string?)Value); } throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } - internal DateTime? ReadDateTimeString(string s) + internal DateTime? ReadDateTimeString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -885,18 +887,18 @@ private bool ReadArrayElementIntoByteArrayReportDone(List buffer) SetToken(JsonToken.Date, new DateTimeOffset(time), false); } - return (DateTimeOffset)Value; + return (DateTimeOffset)Value!; case JsonToken.String: - string s = (string)Value; + string? s = (string?)Value; return ReadDateTimeOffsetString(s); default: throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t)); } } - internal DateTimeOffset? ReadDateTimeOffsetString(string s) + internal DateTimeOffset? ReadDateTimeOffsetString(string? s) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, false); return null; @@ -938,7 +940,7 @@ internal void ReadIntoWrappedTypeObject() if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName) { ReaderReadAndAssert(); - if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal)) + if (Value != null && Value.ToString()!.StartsWith("System.Byte[]", StringComparison.Ordinal)) { ReaderReadAndAssert(); if (Value.ToString() == JsonTypeReflector.ValuePropertyName) @@ -985,7 +987,7 @@ protected void SetToken(JsonToken newToken) /// /// The new token. /// The value. - protected void SetToken(JsonToken newToken, object value) + protected void SetToken(JsonToken newToken, object? value) { SetToken(newToken, value, true); } @@ -996,7 +998,7 @@ protected void SetToken(JsonToken newToken, object value) /// The new token. /// The value. /// A flag indicating whether the position index inside an array should be updated. - protected void SetToken(JsonToken newToken, object value, bool updateIndex) + protected void SetToken(JsonToken newToken, object? value, bool updateIndex) { _tokenType = newToken; _value = value; @@ -1027,7 +1029,7 @@ protected void SetToken(JsonToken newToken, object value, bool updateIndex) case JsonToken.PropertyName: _currentState = State.Property; - _currentPosition.PropertyName = (string)value; + _currentPosition.PropertyName = (string)value!; break; case JsonToken.Undefined: case JsonToken.Integer: @@ -1170,7 +1172,7 @@ internal void ReadAndAssert() } } - internal void ReadForTypeAndAssert(JsonContract contract, bool hasConverter) + internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter) { if (!ReadForType(contract, hasConverter)) { @@ -1178,7 +1180,7 @@ internal void ReadForTypeAndAssert(JsonContract contract, bool hasConverter) } } - internal bool ReadForType(JsonContract contract, bool hasConverter) + internal bool ReadForType(JsonContract? contract, bool hasConverter) { // don't read properties with converters as a specific value // the value might be a string which will then get converted which will error if read as date for example diff --git a/Src/Newtonsoft.Json/JsonReaderException.cs b/Src/Newtonsoft.Json/JsonReaderException.cs index f73107ba2..bcf9a5004 100644 --- a/Src/Newtonsoft.Json/JsonReaderException.cs +++ b/Src/Newtonsoft.Json/JsonReaderException.cs @@ -54,7 +54,7 @@ public class JsonReaderException : JsonException /// Gets the path to the JSON where the error occurred. /// /// The path to the JSON where the error occurred. - public string Path { get; } + public string? Path { get; } /// /// Initializes a new instance of the class. @@ -107,7 +107,7 @@ public JsonReaderException(SerializationInfo info, StreamingContext context) /// The line number indicating where the error occurred. /// The line position indicating where the error occurred. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception innerException) + public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException) : base(message, innerException) { Path = path; @@ -120,12 +120,12 @@ internal static JsonReaderException Create(JsonReader reader, string message) return Create(reader, message, null); } - internal static JsonReaderException Create(JsonReader reader, string message, Exception ex) + internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex) { return Create(reader as IJsonLineInfo, reader.Path, message, ex); } - internal static JsonReaderException Create(IJsonLineInfo lineInfo, string path, string message, Exception ex) + internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(lineInfo, path, message); diff --git a/Src/Newtonsoft.Json/JsonSerializationException.cs b/Src/Newtonsoft.Json/JsonSerializationException.cs index 308b799bb..a54789a76 100644 --- a/Src/Newtonsoft.Json/JsonSerializationException.cs +++ b/Src/Newtonsoft.Json/JsonSerializationException.cs @@ -54,7 +54,7 @@ public class JsonSerializationException : JsonException /// Gets the path to the JSON where the error occurred. /// /// The path to the JSON where the error occurred. - public string Path { get; } + public string? Path { get; } /// /// Initializes a new instance of the class. @@ -107,7 +107,7 @@ public JsonSerializationException(SerializationInfo info, StreamingContext conte /// The line number indicating where the error occurred. /// The line position indicating where the error occurred. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception innerException) + public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException) : base(message, innerException) { Path = path; @@ -120,12 +120,12 @@ internal static JsonSerializationException Create(JsonReader reader, string mess return Create(reader, message, null); } - internal static JsonSerializationException Create(JsonReader reader, string message, Exception ex) + internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex) { return Create(reader as IJsonLineInfo, reader.Path, message, ex); } - internal static JsonSerializationException Create(IJsonLineInfo lineInfo, string path, string message, Exception ex) + internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(lineInfo, path, message); diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index d3e1d5ec0..13e3a9c68 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -35,6 +35,8 @@ using Newtonsoft.Json.Utilities; using System.Runtime.Serialization; using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Newtonsoft.Json { @@ -54,13 +56,13 @@ public class JsonSerializer internal DefaultValueHandling _defaultValueHandling; internal ConstructorHandling _constructorHandling; internal MetadataPropertyHandling _metadataPropertyHandling; - internal JsonConverterCollection _converters; + internal JsonConverterCollection? _converters; internal IContractResolver _contractResolver; - internal ITraceWriter _traceWriter; - internal IEqualityComparer _equalityComparer; + internal ITraceWriter? _traceWriter; + internal IEqualityComparer? _equalityComparer; internal ISerializationBinder _serializationBinder; internal StreamingContext _context; - private IReferenceResolver _referenceResolver; + private IReferenceResolver? _referenceResolver; private Formatting? _formatting; private DateFormatHandling? _dateFormatHandling; @@ -73,18 +75,18 @@ public class JsonSerializer private int? _maxDepth; private bool _maxDepthSet; private bool? _checkAdditionalContent; - private string _dateFormatString; + private string? _dateFormatString; private bool _dateFormatStringSet; /// /// Occurs when the errors during serialization and deserialization. /// - public virtual event EventHandler Error; + public virtual event EventHandler? Error; /// /// Gets or sets the used by the serializer when resolving references. /// - public virtual IReferenceResolver ReferenceResolver + public virtual IReferenceResolver? ReferenceResolver { get => GetReferenceResolver(); set @@ -106,11 +108,6 @@ public virtual SerializationBinder Binder { get { - if (_serializationBinder == null) - { - return null; - } - if (_serializationBinder is SerializationBinder legacySerializationBinder) { return legacySerializationBinder; @@ -155,7 +152,7 @@ public virtual ISerializationBinder SerializationBinder /// Gets or sets the used by the serializer when writing trace messages. /// /// The trace writer. - public virtual ITraceWriter TraceWriter + public virtual ITraceWriter? TraceWriter { get => _traceWriter; set => _traceWriter = value; @@ -165,7 +162,7 @@ public virtual ITraceWriter TraceWriter /// Gets or sets the equality comparer used by the serializer when comparing references. /// /// The equality comparer. - public virtual IEqualityComparer EqualityComparer + public virtual IEqualityComparer? EqualityComparer { get => _equalityComparer; set => _equalityComparer = value; @@ -517,7 +514,7 @@ public virtual CultureInfo Culture /// /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a . /// A null value means there is no maximum. - /// The default value is null. + /// The default value is 64. /// public virtual int? MaxDepth { @@ -599,7 +596,7 @@ public static JsonSerializer Create() /// The will not use default settings /// from . /// - public static JsonSerializer Create(JsonSerializerSettings settings) + public static JsonSerializer Create(JsonSerializerSettings? settings) { JsonSerializer serializer = Create(); @@ -624,7 +621,7 @@ public static JsonSerializer Create(JsonSerializerSettings settings) public static JsonSerializer CreateDefault() { // copy static to local variable to avoid concurrency issues - JsonSerializerSettings defaultSettings = JsonConvert.DefaultSettings?.Invoke(); + JsonSerializerSettings? defaultSettings = JsonConvert.DefaultSettings?.Invoke(); return Create(defaultSettings); } @@ -640,7 +637,7 @@ public static JsonSerializer CreateDefault() /// The will use default settings /// from as well as the specified . /// - public static JsonSerializer CreateDefault(JsonSerializerSettings settings) + public static JsonSerializer CreateDefault(JsonSerializerSettings? settings) { JsonSerializer serializer = CreateDefault(); if (settings != null) @@ -814,14 +811,14 @@ internal virtual void PopulateInternal(JsonReader reader, object target) SetupReader( reader, - out CultureInfo previousCulture, + out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, - out string previousDateFormatString); + out string? previousDateFormatString); - TraceJsonReader traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) + TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null; @@ -830,7 +827,7 @@ internal virtual void PopulateInternal(JsonReader reader, object target) if (traceJsonReader != null) { - TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); + TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); @@ -842,20 +839,20 @@ internal virtual void PopulateInternal(JsonReader reader, object target) /// The that contains the JSON structure to deserialize. /// The being deserialized. [DebuggerStepThrough] - public object Deserialize(JsonReader reader) + public object? Deserialize(JsonReader reader) { return Deserialize(reader, null); } /// - /// Deserializes the JSON structure contained by the specified + /// Deserializes the JSON structure contained by the specified /// into an instance of the specified type. /// /// The containing the object. /// The of object being deserialized. /// The instance of being deserialized. [DebuggerStepThrough] - public object Deserialize(TextReader reader, Type objectType) + public object? Deserialize(TextReader reader, Type objectType) { return Deserialize(new JsonTextReader(reader), objectType); } @@ -868,9 +865,9 @@ public object Deserialize(TextReader reader, Type objectType) /// The type of the object to deserialize. /// The instance of being deserialized. [DebuggerStepThrough] - public T Deserialize(JsonReader reader) + public T? Deserialize(JsonReader reader) { - return (T)Deserialize(reader, typeof(T)); + return (T?)Deserialize(reader, typeof(T)); } /// @@ -881,34 +878,34 @@ public T Deserialize(JsonReader reader) /// The of object being deserialized. /// The instance of being deserialized. [DebuggerStepThrough] - public object Deserialize(JsonReader reader, Type objectType) + public object? Deserialize(JsonReader reader, Type? objectType) { return DeserializeInternal(reader, objectType); } - internal virtual object DeserializeInternal(JsonReader reader, Type objectType) + internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); SetupReader( reader, - out CultureInfo previousCulture, + out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, - out string previousDateFormatString); + out string? previousDateFormatString); - TraceJsonReader traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) + TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null; JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this); - object value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent); + object? value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent); if (traceJsonReader != null) { - TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); + TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); @@ -916,7 +913,7 @@ internal virtual object DeserializeInternal(JsonReader reader, Type objectType) return value; } - private void SetupReader(JsonReader reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString) + internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString) { if (_culture != null && !_culture.Equals(reader.Culture)) { @@ -987,7 +984,7 @@ private void SetupReader(JsonReader reader, out CultureInfo previousCulture, out } } - private void ResetReader(JsonReader reader, CultureInfo previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string previousDateFormatString) + private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString) { // reset reader back to previous options if (previousCulture != null) @@ -1028,7 +1025,7 @@ private void ResetReader(JsonReader reader, CultureInfo previousCulture, DateTim /// /// The used to write the JSON structure. /// The to serialize. - public void Serialize(TextWriter textWriter, object value) + public void Serialize(TextWriter textWriter, object? value) { Serialize(new JsonTextWriter(textWriter), value); } @@ -1044,7 +1041,7 @@ public void Serialize(TextWriter textWriter, object value) /// This parameter is used when is to write out the type name if the type of the value does not match. /// Specifying the type is optional. /// - public void Serialize(JsonWriter jsonWriter, object value, Type objectType) + public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType) { SerializeInternal(jsonWriter, value, objectType); } @@ -1060,7 +1057,7 @@ public void Serialize(JsonWriter jsonWriter, object value, Type objectType) /// This parameter is used when is Auto to write out the type name if the type of the value does not match. /// Specifying the type is optional. /// - public void Serialize(TextWriter textWriter, object value, Type objectType) + public void Serialize(TextWriter textWriter, object? value, Type objectType) { Serialize(new JsonTextWriter(textWriter), value, objectType); } @@ -1071,7 +1068,7 @@ public void Serialize(TextWriter textWriter, object value, Type objectType) /// /// The used to write the JSON structure. /// The to serialize. - public void Serialize(JsonWriter jsonWriter, object value) + public void Serialize(JsonWriter jsonWriter, object? value) { SerializeInternal(jsonWriter, value, null); } @@ -1087,7 +1084,7 @@ private TraceJsonReader CreateTraceJsonReader(JsonReader reader) return traceReader; } - internal virtual void SerializeInternal(JsonWriter jsonWriter, object value, Type objectType) + internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType) { ValidationUtils.ArgumentNotNull(jsonWriter, nameof(jsonWriter)); @@ -1127,21 +1124,21 @@ internal virtual void SerializeInternal(JsonWriter jsonWriter, object value, Typ jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault(); } - CultureInfo previousCulture = null; + CultureInfo? previousCulture = null; if (_culture != null && !_culture.Equals(jsonWriter.Culture)) { previousCulture = jsonWriter.Culture; jsonWriter.Culture = _culture; } - string previousDateFormatString = null; + string? previousDateFormatString = null; if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString) { previousDateFormatString = jsonWriter.DateFormatString; jsonWriter.DateFormatString = _dateFormatString; } - TraceJsonWriter traceJsonWriter = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) + TraceJsonWriter? traceJsonWriter = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null; @@ -1150,7 +1147,7 @@ internal virtual void SerializeInternal(JsonWriter jsonWriter, object value, Typ if (traceJsonWriter != null) { - TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null); + TraceWriter!.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null); } // reset writer back to previous options @@ -1194,12 +1191,12 @@ internal IReferenceResolver GetReferenceResolver() return _referenceResolver; } - internal JsonConverter GetMatchingConverter(Type type) + internal JsonConverter? GetMatchingConverter(Type type) { return GetMatchingConverter(_converters, type); } - internal static JsonConverter GetMatchingConverter(IList converters, Type objectType) + internal static JsonConverter? GetMatchingConverter(IList? converters, Type objectType) { #if DEBUG ValidationUtils.ArgumentNotNull(objectType, nameof(objectType)); diff --git a/Src/Newtonsoft.Json/JsonSerializerSettings.cs b/Src/Newtonsoft.Json/JsonSerializerSettings.cs index ea68dc948..500e1c665 100644 --- a/Src/Newtonsoft.Json/JsonSerializerSettings.cs +++ b/Src/Newtonsoft.Json/JsonSerializerSettings.cs @@ -31,6 +31,12 @@ using Newtonsoft.Json.Serialization; using System.Runtime.Serialization; using System.Diagnostics; +using System.Runtime; +#if !HAVE_LINQ +using Newtonsoft.Json.Utilities.LinqBridge; +#else +using System.Linq; +#endif namespace Newtonsoft.Json { @@ -61,6 +67,7 @@ public class JsonSerializerSettings internal static readonly CultureInfo DefaultCulture; internal const bool DefaultCheckAdditionalContent = false; internal const string DefaultDateFormatString = @"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; + internal const int DefaultMaxDepth = 64; internal Formatting? _formatting; internal DateFormatHandling? _dateFormatHandling; @@ -69,11 +76,11 @@ public class JsonSerializerSettings internal FloatFormatHandling? _floatFormatHandling; internal FloatParseHandling? _floatParseHandling; internal StringEscapeHandling? _stringEscapeHandling; - internal CultureInfo _culture; + internal CultureInfo? _culture; internal bool? _checkAdditionalContent; internal int? _maxDepth; internal bool _maxDepthSet; - internal string _dateFormatString; + internal string? _dateFormatString; internal bool _dateFormatStringSet; internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling; internal DefaultValueHandling? _defaultValueHandling; @@ -225,27 +232,27 @@ public ConstructorHandling ConstructorHandling /// serializing .NET objects to JSON and vice versa. /// /// The contract resolver. - public IContractResolver ContractResolver { get; set; } + public IContractResolver? ContractResolver { get; set; } /// /// Gets or sets the equality comparer used by the serializer when comparing references. /// /// The equality comparer. - public IEqualityComparer EqualityComparer { get; set; } + public IEqualityComparer? EqualityComparer { get; set; } /// /// Gets or sets the used by the serializer when resolving references. /// /// The reference resolver. [Obsolete("ReferenceResolver property is obsolete. Use the ReferenceResolverProvider property to set the IReferenceResolver: settings.ReferenceResolverProvider = () => resolver")] - public IReferenceResolver ReferenceResolver + public IReferenceResolver? ReferenceResolver { get => ReferenceResolverProvider?.Invoke(); set { ReferenceResolverProvider = (value != null) ? () => value - : (Func)null; + : (Func?)null; } } @@ -253,20 +260,20 @@ public IReferenceResolver ReferenceResolver /// Gets or sets a function that creates the used by the serializer when resolving references. /// /// A function that creates the used by the serializer when resolving references. - public Func ReferenceResolverProvider { get; set; } + public Func? ReferenceResolverProvider { get; set; } /// /// Gets or sets the used by the serializer when writing trace messages. /// /// The trace writer. - public ITraceWriter TraceWriter { get; set; } + public ITraceWriter? TraceWriter { get; set; } /// /// Gets or sets the used by the serializer when resolving type names. /// /// The binder. [Obsolete("Binder is obsolete. Use SerializationBinder instead.")] - public SerializationBinder Binder + public SerializationBinder? Binder { get { @@ -289,13 +296,13 @@ public SerializationBinder Binder /// Gets or sets the used by the serializer when resolving type names. /// /// The binder. - public ISerializationBinder SerializationBinder { get; set; } + public ISerializationBinder? SerializationBinder { get; set; } /// /// Gets or sets the error handler called during serialization and deserialization. /// /// The error handler called during serialization and deserialization. - public EventHandler Error { get; set; } + public EventHandler? Error { get; set; } /// /// Gets or sets the used by the serializer when invoking serialization callback methods. @@ -325,11 +332,11 @@ public string DateFormatString /// /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a . /// A null value means there is no maximum. - /// The default value is null. + /// The default value is 64. /// public int? MaxDepth { - get => _maxDepth; + get => _maxDepthSet ? _maxDepth : DefaultMaxDepth; set { if (value <= 0) @@ -451,5 +458,44 @@ public JsonSerializerSettings() { Converters = new List(); } + + /// + /// Initializes a new instance of the class + /// using values copied from the passed in . + /// + public JsonSerializerSettings(JsonSerializerSettings original) + { + _floatParseHandling = original._floatParseHandling; + _floatFormatHandling = original._floatFormatHandling; + _dateParseHandling = original._dateParseHandling; + _dateTimeZoneHandling = original._dateTimeZoneHandling; + _dateFormatHandling = original._dateFormatHandling; + _formatting = original._formatting; + _maxDepth = original._maxDepth; + _maxDepthSet = original._maxDepthSet; + _dateFormatString = original._dateFormatString; + _dateFormatStringSet = original._dateFormatStringSet; + _context = original._context; + Error = original.Error; + SerializationBinder = original.SerializationBinder; + TraceWriter = original.TraceWriter; + _culture = original._culture; + ReferenceResolverProvider = original.ReferenceResolverProvider; + EqualityComparer = original.EqualityComparer; + ContractResolver = original.ContractResolver; + _constructorHandling = original._constructorHandling; + _typeNameAssemblyFormatHandling = original._typeNameAssemblyFormatHandling; + _metadataPropertyHandling = original._metadataPropertyHandling; + _typeNameHandling = original._typeNameHandling; + _preserveReferencesHandling = original._preserveReferencesHandling; + Converters = original.Converters.ToList(); + _defaultValueHandling = original._defaultValueHandling; + _nullValueHandling = original._nullValueHandling; + _objectCreationHandling = original._objectCreationHandling; + _missingMemberHandling = original._missingMemberHandling; + _referenceLoopHandling = original._referenceLoopHandling; + _checkAdditionalContent = original._checkAdditionalContent; + _stringEscapeHandling = original._stringEscapeHandling; + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonTextReader.Async.cs b/Src/Newtonsoft.Json/JsonTextReader.Async.cs index bb18359a7..8974e700a 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.Async.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.Async.cs @@ -34,6 +34,7 @@ using System.Threading.Tasks; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; +using System.Diagnostics; namespace Newtonsoft.Json { @@ -78,7 +79,7 @@ internal Task DoReadAsync(CancellationToken cancellationToken) return ParseObjectAsync(cancellationToken); case State.PostValue: Task task = ParsePostValueAsync(false, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { if (task.Result) { @@ -110,6 +111,8 @@ private async Task DoReadAsync(Task task, CancellationToken cancella private async Task ParsePostValueAsync(bool ignoreComments, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -193,6 +196,8 @@ private async Task ParsePostValueAsync(bool ignoreComments, CancellationTo private async Task ReadFromFinishedAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); @@ -222,6 +227,8 @@ private Task ReadDataAsync(bool append, CancellationToken cancellationToken private async Task ReadDataAsync(bool append, int charsRequired, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (_isEndOfFile) { return 0; @@ -244,6 +251,8 @@ private async Task ReadDataAsync(bool append, int charsRequired, Cancellati private async Task ParseValueAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -373,6 +382,8 @@ private async Task ParseValueAsync(CancellationToken cancellationToken) private async Task ReadStringIntoBufferAsync(char quote, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; int initialPosition = _charPos; int lastWritePosition = _charPos; @@ -531,7 +542,7 @@ private Task ProcessCarriageReturnAsync(bool append, CancellationToken cancellat _charPos++; Task task = EnsureCharsAsync(1, append, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { SetNewLine(task.Result); return AsyncUtils.CompletedTask; @@ -589,6 +600,8 @@ private async Task ReadCharsAsync(int relativePosition, bool append, Cance private async Task ParseObjectAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -646,6 +659,8 @@ private async Task ParseObjectAsync(CancellationToken cancellationToken) private async Task ParseCommentAsync(bool setToken, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + // should have already parsed / character before reaching this method _charPos++; @@ -742,6 +757,8 @@ private async Task ParseCommentAsync(bool setToken, CancellationToken cancellati private async Task EatWhitespaceAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -798,6 +815,8 @@ private async Task MatchValueAsync(string value, CancellationToken cancell private async Task MatchValueWithTrailingSeparatorAsync(string value, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + // will match value and then move to the next character, checking that it is a separator character if (!await MatchValueAsync(value, cancellationToken).ConfigureAwait(false)) { @@ -812,7 +831,7 @@ private async Task MatchValueWithTrailingSeparatorAsync(string value, Canc return IsSeparator(_chars[_charPos]) || _chars[_charPos] == '\0'; } - private async Task MatchAndSetAsync(string value, JsonToken newToken, object tokenValue, CancellationToken cancellationToken) + private async Task MatchAndSetAsync(string value, JsonToken newToken, object? tokenValue, CancellationToken cancellationToken) { if (await MatchValueWithTrailingSeparatorAsync(value, cancellationToken).ConfigureAwait(false)) { @@ -841,6 +860,8 @@ private Task ParseNullAsync(CancellationToken cancellationToken) private async Task ParseConstructorAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await MatchValueWithTrailingSeparatorAsync("new", cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); @@ -939,6 +960,8 @@ private async Task ParseNumberNegativeInfinityAsync(ReadType readType, C private async Task ParseNumberAsync(ReadType readType, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + ShiftBufferIfNeeded(); char firstChar = _chars[_charPos]; @@ -956,6 +979,8 @@ private Task ParseUndefinedAsync(CancellationToken cancellationToken) private async Task ParsePropertyAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + char firstChar = _chars[_charPos]; char quoteChar; @@ -1008,6 +1033,8 @@ private async Task ParsePropertyAsync(CancellationToken cancellationToken) private async Task ReadNumberIntoBufferAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; while (true) @@ -1042,6 +1069,8 @@ private async Task ReadNumberIntoBufferAsync(CancellationToken cancellationToken private async Task ParseUnquotedPropertyAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + int initialPosition = _charPos; // parse unquoted property name until whitespace or colon @@ -1091,6 +1120,8 @@ private async Task ReadNullCharAsync(CancellationToken cancellationToken) private async Task HandleNullAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false)) { if (_chars[_charPos + 1] == 'u') @@ -1109,6 +1140,8 @@ private async Task HandleNullAsync(CancellationToken cancellationToken) private async Task ReadFinishedAsync(CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_chars != null); + if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); @@ -1131,9 +1164,10 @@ private async Task ReadFinishedAsync(CancellationToken cancellationToken) SetToken(JsonToken.None); } - private async Task ReadStringValueAsync(ReadType readType, CancellationToken cancellationToken) + private async Task ReadStringValueAsync(ReadType readType, CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1266,9 +1300,10 @@ private async Task ReadStringValueAsync(ReadType readType, CancellationT } } - private async Task ReadNumberValueAsync(ReadType readType, CancellationToken cancellationToken) + private async Task ReadNumberValueAsync(ReadType readType, CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1395,6 +1430,7 @@ private async Task ReadNumberValueAsync(ReadType readType, CancellationT internal async Task DoReadAsBooleanAsync(CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1522,14 +1558,16 @@ private async Task ReadNumberValueAsync(ReadType readType, CancellationT /// property returns the []. This result will be null at the end of an array. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task ReadAsBytesAsync(CancellationToken cancellationToken = default) + public override Task ReadAsBytesAsync(CancellationToken cancellationToken = default) { return _safeAsync ? DoReadAsBytesAsync(cancellationToken) : base.ReadAsBytesAsync(cancellationToken); } - internal async Task DoReadAsBytesAsync(CancellationToken cancellationToken) + internal async Task DoReadAsBytesAsync(CancellationToken cancellationToken) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); + bool isWrapped = false; switch (_currentState) @@ -1563,7 +1601,7 @@ internal async Task DoReadAsBytesAsync(CancellationToken cancellationTok case '"': case '\'': await ParseStringAsync(currentChar, ReadType.ReadAsBytes, cancellationToken).ConfigureAwait(false); - byte[] data = (byte[])Value; + byte[]? data = (byte[]?)Value; if (isWrapped) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); @@ -1642,7 +1680,7 @@ private async Task ReadIntoWrappedTypeObjectAsync(CancellationToken cancellation if (Value != null && Value.ToString() == JsonTypeReflector.TypePropertyName) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); - if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal)) + if (Value != null && Value.ToString()!.StartsWith("System.Byte[]", StringComparison.Ordinal)) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); if (Value.ToString() == JsonTypeReflector.ValuePropertyName) @@ -1753,14 +1791,14 @@ private async Task ReadIntoWrappedTypeObjectAsync(CancellationToken cancellation /// property returns the . This result will be null at the end of an array. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task ReadAsStringAsync(CancellationToken cancellationToken = default) + public override Task ReadAsStringAsync(CancellationToken cancellationToken = default) { return _safeAsync ? DoReadAsStringAsync(cancellationToken) : base.ReadAsStringAsync(cancellationToken); } - internal async Task DoReadAsStringAsync(CancellationToken cancellationToken) + internal async Task DoReadAsStringAsync(CancellationToken cancellationToken) { - return (string)await ReadStringValueAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false); + return (string?)await ReadStringValueAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false); } } } diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 1783da400..925f4b6b2 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -27,6 +27,7 @@ using System.Runtime.CompilerServices; using System.IO; using System.Globalization; +using System.Diagnostics; #if HAVE_BIG_INTEGER using System.Numerics; #endif @@ -66,7 +67,7 @@ public partial class JsonTextReader : JsonReader, IJsonLineInfo #endif private readonly TextReader _reader; - private char[] _chars; + private char[]? _chars; private int _charsUsed; private int _charPos; private int _lineStartPos; @@ -74,7 +75,7 @@ public partial class JsonTextReader : JsonReader, IJsonLineInfo private bool _isEndOfFile; private StringBuffer _stringBuffer; private StringReference _stringReference; - private IArrayPool _arrayPool; + private IArrayPool? _arrayPool; /// /// Initializes a new instance of the class with the specified . @@ -96,7 +97,7 @@ public JsonTextReader(TextReader reader) } #if DEBUG - internal char[] CharBuffer + internal char[]? CharBuffer { get => _chars; set => _chars = value; @@ -108,12 +109,12 @@ internal char[] CharBuffer /// /// Gets or sets the reader's property name table. /// - public JsonNameTable PropertyNameTable { get; set; } + public JsonNameTable? PropertyNameTable { get; set; } /// /// Gets or sets the reader's character buffer pool. /// - public IArrayPool ArrayPool + public IArrayPool? ArrayPool { get => _arrayPool; set @@ -137,6 +138,8 @@ private void EnsureBufferNotEmpty() private void SetNewLine(bool hasNextChar) { + MiscellaneousUtils.Assert(_chars != null); + if (hasNextChar && _chars[_charPos] == StringUtils.LineFeed) { _charPos++; @@ -249,6 +252,8 @@ private static void BlockCopyChars(char[] src, int srcOffset, char[] dst, int ds private void ShiftBufferIfNeeded() { + MiscellaneousUtils.Assert(_chars != null); + // once in the last 10% of the buffer, or buffer is already very large then // shift the remaining content to the start to avoid unnecessarily increasing // the buffer size when reading numbers/strings @@ -275,6 +280,8 @@ private int ReadData(bool append) private void PrepareBufferForReadData(bool append, int charsRequired) { + MiscellaneousUtils.Assert(_chars != null); + // char buffer is full if (_charsUsed + charsRequired >= _chars.Length - 1) { @@ -338,6 +345,7 @@ private int ReadData(bool append, int charsRequired) } PrepareBufferForReadData(append, charsRequired); + MiscellaneousUtils.Assert(_chars != null); int attemptCharReadCount = _chars.Length - _charsUsed - 1; @@ -406,6 +414,7 @@ private bool ReadChars(int relativePosition, bool append) public override bool Read() { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); while (true) { @@ -476,18 +485,20 @@ public override bool Read() /// Reads the next JSON token from the underlying as a . /// /// A . This method will return null at the end of an array. - public override string ReadAsString() + public override string? ReadAsString() { - return (string)ReadStringValue(ReadType.ReadAsString); + return (string?)ReadStringValue(ReadType.ReadAsString); } /// /// Reads the next JSON token from the underlying as a []. /// /// A [] or null if the next JSON token is null. This method will return null at the end of an array. - public override byte[] ReadAsBytes() + public override byte[]? ReadAsBytes() { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); + bool isWrapped = false; switch (_currentState) @@ -520,7 +531,7 @@ public override byte[] ReadAsBytes() case '"': case '\'': ParseString(currentChar, ReadType.ReadAsBytes); - byte[] data = (byte[])Value; + byte[]? data = (byte[]?)Value; if (isWrapped) { ReaderReadAndAssert(); @@ -589,9 +600,10 @@ public override byte[] ReadAsBytes() } } - private object ReadStringValue(ReadType readType) + private object? ReadStringValue(ReadType readType) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -718,7 +730,7 @@ private object ReadStringValue(ReadType readType) } } - private object FinishReadQuotedStringValue(ReadType readType) + private object? FinishReadQuotedStringValue(ReadType readType) { switch (readType) { @@ -731,7 +743,7 @@ private object FinishReadQuotedStringValue(ReadType readType) return time; } - return ReadDateTimeString((string)Value); + return ReadDateTimeString((string?)Value); #if HAVE_DATE_TIME_OFFSET case ReadType.ReadAsDateTimeOffset: if (Value is DateTimeOffset offset) @@ -739,7 +751,7 @@ private object FinishReadQuotedStringValue(ReadType readType) return offset; } - return ReadDateTimeOffsetString((string)Value); + return ReadDateTimeOffsetString((string?)Value); #endif default: throw new ArgumentOutOfRangeException(nameof(readType)); @@ -758,6 +770,7 @@ private JsonReaderException CreateUnexpectedCharacterException(char c) public override bool? ReadAsBoolean() { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -828,7 +841,7 @@ private JsonReaderException CreateUnexpectedCharacterException(char c) { throw CreateUnexpectedCharacterException(_chars[_charPos]); } - SetToken(JsonToken.Boolean, isTrue); + SetToken(JsonToken.Boolean, BoxedPrimitives.Get(isTrue)); return isTrue; case '/': ParseComment(false); @@ -892,9 +905,10 @@ private void ProcessValueComma() SetStateBasedOnCurrent(); } - private object ReadNumberValue(ReadType readType) + private object? ReadNumberValue(ReadType readType) { EnsureBuffer(); + MiscellaneousUtils.Assert(_chars != null); switch (_currentState) { @@ -1002,7 +1016,7 @@ private object ReadNumberValue(ReadType readType) } } - private object FinishReadQuotedNumber(ReadType readType) + private object? FinishReadQuotedNumber(ReadType readType) { switch (readType) { @@ -1048,6 +1062,8 @@ private object FinishReadQuotedNumber(ReadType readType) private void HandleNull() { + MiscellaneousUtils.Assert(_chars != null); + if (EnsureChars(1, true)) { char next = _chars[_charPos + 1]; @@ -1068,6 +1084,8 @@ private void HandleNull() private void ReadFinished() { + MiscellaneousUtils.Assert(_chars != null); + if (EnsureChars(0, false)) { EatWhitespace(); @@ -1117,6 +1135,8 @@ private void EnsureBuffer() private void ReadStringIntoBuffer(char quote) { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; int initialPosition = _charPos; int lastWritePosition = _charPos; @@ -1270,6 +1290,8 @@ private void ReadStringIntoBuffer(char quote) private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int lastWritePosition) { + MiscellaneousUtils.Assert(_chars != null); + if (initialPosition == lastWritePosition) { _stringReference = new StringReference(_chars, initialPosition, charPos - initialPosition); @@ -1283,7 +1305,7 @@ private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int la _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, charPos - lastWritePosition); } - _stringReference = new StringReference(_stringBuffer.InternalBuffer, 0, _stringBuffer.Position); + _stringReference = new StringReference(_stringBuffer.InternalBuffer!, 0, _stringBuffer.Position); } _charPos = charPos + 1; @@ -1291,6 +1313,8 @@ private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int la private void WriteCharToBuffer(char writeChar, int lastWritePosition, int writeToPosition) { + MiscellaneousUtils.Assert(_chars != null); + if (writeToPosition > lastWritePosition) { _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, writeToPosition - lastWritePosition); @@ -1301,6 +1325,8 @@ private void WriteCharToBuffer(char writeChar, int lastWritePosition, int writeT private char ConvertUnicode(bool enoughChars) { + MiscellaneousUtils.Assert(_chars != null); + if (enoughChars) { if (ConvertUtils.TryHexTextToInt(_chars, _charPos, _charPos + 4, out int value)) @@ -1327,6 +1353,8 @@ private char ParseUnicode() private void ReadNumberIntoBuffer() { + MiscellaneousUtils.Assert(_chars != null); + int charPos = _charPos; while (true) @@ -1411,6 +1439,8 @@ private void ClearRecentString() private bool ParsePostValue(bool ignoreComments) { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1491,6 +1521,8 @@ private bool ParsePostValue(bool ignoreComments) private bool ParseObject() { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1545,6 +1577,8 @@ private bool ParseObject() private bool ParseProperty() { + MiscellaneousUtils.Assert(_chars != null); + char firstChar = _chars[_charPos]; char quoteChar; @@ -1566,7 +1600,7 @@ private bool ParseProperty() throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); } - string propertyName; + string? propertyName; if (PropertyNameTable != null) { @@ -1606,6 +1640,8 @@ private bool ValidIdentifierChar(char value) private void ParseUnquotedProperty() { + MiscellaneousUtils.Assert(_chars != null); + int initialPosition = _charPos; // parse unquoted property name until whitespace or colon @@ -1637,6 +1673,8 @@ private void ParseUnquotedProperty() private bool ReadUnquotedPropertyReportIfDone(char currentChar, int initialPosition) { + MiscellaneousUtils.Assert(_chars != null); + if (ValidIdentifierChar(currentChar)) { _charPos++; @@ -1654,6 +1692,8 @@ private bool ReadUnquotedPropertyReportIfDone(char currentChar, int initialPosit private bool ParseValue() { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1794,6 +1834,8 @@ private void ProcessCarriageReturn(bool append) private void EatWhitespace() { + MiscellaneousUtils.Assert(_chars != null); + while (true) { char currentChar = _chars[_charPos]; @@ -1835,6 +1877,8 @@ private void EatWhitespace() private void ParseConstructor() { + MiscellaneousUtils.Assert(_chars != null); + if (MatchValueWithTrailingSeparator("new")) { EatWhitespace(); @@ -1919,6 +1963,7 @@ private void ParseConstructor() private void ParseNumber(ReadType readType) { ShiftBufferIfNeeded(); + MiscellaneousUtils.Assert(_chars != null); char firstChar = _chars[_charPos]; int initialPosition = _charPos; @@ -1929,7 +1974,9 @@ private void ParseNumber(ReadType readType) } private void ParseReadNumber(ReadType readType, char firstChar, int initialPosition) - { + { + MiscellaneousUtils.Assert(_chars != null); + // set state to PostValue now so that if there is an error parsing the number then the reader can continue SetPostValueState(true); @@ -1983,7 +2030,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = firstChar - 48; + numberValue = BoxedPrimitives.Get(firstChar - 48); } else if (nonBase10) { @@ -1993,7 +2040,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit { int integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt32(number, 16) : Convert.ToInt32(number, 8); - numberValue = integer; + numberValue = BoxedPrimitives.Get(integer); } catch (Exception ex) { @@ -2005,7 +2052,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit ParseResult parseResult = ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out int value); if (parseResult == ParseResult.Success) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); } else if (parseResult == ParseResult.Overflow) { @@ -2025,7 +2072,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = (decimal)firstChar - 48; + numberValue = BoxedPrimitives.Get((decimal)firstChar - 48); } else if (nonBase10) { @@ -2036,7 +2083,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit // decimal.Parse doesn't support parsing hexadecimal values long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); - numberValue = Convert.ToDecimal(integer); + numberValue = BoxedPrimitives.Get(Convert.ToDecimal(integer)); } catch (Exception ex) { @@ -2048,7 +2095,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit ParseResult parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out decimal value); if (parseResult == ParseResult.Success) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); } else { @@ -2064,7 +2111,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = (double)firstChar - 48; + numberValue = BoxedPrimitives.Get((double)firstChar - 48); } else if (nonBase10) { @@ -2075,7 +2122,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit // double.Parse doesn't support parsing hexadecimal values long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); - numberValue = Convert.ToDouble(integer); + numberValue = BoxedPrimitives.Get(Convert.ToDouble(integer)); } catch (Exception ex) { @@ -2088,7 +2135,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out double value)) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); } else { @@ -2105,7 +2152,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (singleDigit) { // digit char values start at 48 - numberValue = (long)firstChar - 48; + numberValue = BoxedPrimitives.Get((long)firstChar - 48); numberType = JsonToken.Integer; } else if (nonBase10) @@ -2114,7 +2161,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit try { - numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8); + numberValue = BoxedPrimitives.Get(number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(number, 16) : Convert.ToInt64(number, 8)); } catch (Exception ex) { @@ -2128,7 +2175,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit ParseResult parseResult = ConvertUtils.Int64TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out long value); if (parseResult == ParseResult.Success) { - numberValue = value; + numberValue = BoxedPrimitives.Get(value); numberType = JsonToken.Integer; } else if (parseResult == ParseResult.Overflow) @@ -2154,7 +2201,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out decimal d); if (parseResult == ParseResult.Success) { - numberValue = d; + numberValue = BoxedPrimitives.Get(d); } else { @@ -2167,7 +2214,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit if (double.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out double d)) { - numberValue = d; + numberValue = BoxedPrimitives.Get(d); } else { @@ -2190,7 +2237,7 @@ private void ParseReadNumber(ReadType readType, char firstChar, int initialPosit SetToken(numberType, numberValue, false); } - private JsonReaderException ThrowReaderError(string message, Exception ex = null) + private JsonReaderException ThrowReaderError(string message, Exception? ex = null) { SetToken(JsonToken.Undefined, null, false); return JsonReaderException.Create(this, message, ex); @@ -2210,6 +2257,8 @@ private static object BigIntegerParse(string number, CultureInfo culture) private void ParseComment(bool setToken) { + MiscellaneousUtils.Assert(_chars != null); + // should have already parsed / character before reaching this method _charPos++; @@ -2304,6 +2353,7 @@ private void EndComment(bool setToken, int initialPosition, int endPosition) { if (setToken) { + MiscellaneousUtils.Assert(_chars != null); SetToken(JsonToken.Comment, new string(_chars, initialPosition, endPosition - initialPosition)); } } @@ -2315,6 +2365,8 @@ private bool MatchValue(string value) private bool MatchValue(bool enoughChars, string value) { + MiscellaneousUtils.Assert(_chars != null); + if (!enoughChars) { _charPos = _charsUsed; @@ -2337,6 +2389,8 @@ private bool MatchValue(bool enoughChars, string value) private bool MatchValueWithTrailingSeparator(string value) { + MiscellaneousUtils.Assert(_chars != null); + // will match value and then move to the next character, checking that it is a separator character bool match = MatchValue(value); @@ -2355,6 +2409,8 @@ private bool MatchValueWithTrailingSeparator(string value) private bool IsSeparator(char c) { + MiscellaneousUtils.Assert(_chars != null); + switch (c) { case '}': @@ -2400,7 +2456,7 @@ private void ParseTrue() // or the text ends if (MatchValueWithTrailingSeparator(JsonConvert.True)) { - SetToken(JsonToken.Boolean, true); + SetToken(JsonToken.Boolean, BoxedPrimitives.BooleanTrue); } else { @@ -2436,7 +2492,7 @@ private void ParseFalse() { if (MatchValueWithTrailingSeparator(JsonConvert.False)) { - SetToken(JsonToken.Boolean, false); + SetToken(JsonToken.Boolean, BoxedPrimitives.BooleanFalse); } else { @@ -2459,7 +2515,7 @@ private object ParseNumberNegativeInfinity(ReadType readType, bool matched) case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { - SetToken(JsonToken.Float, double.NegativeInfinity); + SetToken(JsonToken.Float, BoxedPrimitives.DoubleNegativeInfinity); return double.NegativeInfinity; } break; @@ -2488,7 +2544,7 @@ private object ParseNumberPositiveInfinity(ReadType readType, bool matched) case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { - SetToken(JsonToken.Float, double.PositiveInfinity); + SetToken(JsonToken.Float, BoxedPrimitives.DoublePositiveInfinity); return double.PositiveInfinity; } break; @@ -2518,7 +2574,7 @@ private object ParseNumberNaN(ReadType readType, bool matched) case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { - SetToken(JsonToken.Float, double.NaN); + SetToken(JsonToken.Float, BoxedPrimitives.DoubleNaN); return double.NaN; } break; diff --git a/Src/Newtonsoft.Json/JsonTextWriter.Async.cs b/Src/Newtonsoft.Json/JsonTextWriter.Async.cs index 1b98a3f64..097ed3c6e 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.Async.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.Async.cs @@ -33,6 +33,7 @@ #endif using System.Threading.Tasks; using Newtonsoft.Json.Utilities; +using System.Diagnostics; namespace Newtonsoft.Json { @@ -131,7 +132,34 @@ internal async Task DoCloseAsync(CancellationToken cancellationToken) await WriteEndAsync(cancellationToken).ConfigureAwait(false); } - CloseBufferAndWriter(); + await CloseBufferAndWriterAsync().ConfigureAwait(false); + } + + private async Task CloseBufferAndWriterAsync() + { + if (_writeBuffer != null) + { + BufferUtils.ReturnBuffer(_arrayPool, _writeBuffer); + _writeBuffer = null; + } + + if (CloseOutput && _writer != null) + { +#if HAVE_ASYNC_DISPOSABLE + await _writer.DisposeAsync().ConfigureAwait(false); +#else + // DisposeAsync isn't available. Instead, flush any remaining content with FlushAsync + // to prevent Close/Dispose from making a blocking flush. + // + // No cancellation token on TextWriter.FlushAsync?! + await _writer.FlushAsync().ConfigureAwait(false); +#if HAVE_STREAM_READER_WRITER_CLOSE + _writer.Close(); +#else + _writer.Dispose(); +#endif +#endif + } } /// @@ -164,6 +192,7 @@ internal Task DoWriteIndentAsync(CancellationToken cancellationToken) int currentIndentCount = Top * _indentation; int newLineLen = SetIndentChars(); + MiscellaneousUtils.Assert(_indentChars != null); if (currentIndentCount <= IndentCharBufferSize) { @@ -175,6 +204,8 @@ internal Task DoWriteIndentAsync(CancellationToken cancellationToken) private async Task WriteIndentAsync(int currentIndentCount, int newLineLen, CancellationToken cancellationToken) { + MiscellaneousUtils.Assert(_indentChars != null); + await _writer.WriteAsync(_indentChars, 0, newLineLen + Math.Min(currentIndentCount, IndentCharBufferSize), cancellationToken).ConfigureAwait(false); while ((currentIndentCount -= IndentCharBufferSize) > 0) @@ -186,7 +217,7 @@ private async Task WriteIndentAsync(int currentIndentCount, int newLineLen, Canc private Task WriteValueInternalAsync(JsonToken token, string value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(token, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync(value, cancellationToken); } @@ -225,12 +256,12 @@ internal Task DoWriteIndentSpaceAsync(CancellationToken cancellationToken) /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteRawAsync(string json, CancellationToken cancellationToken = default) + public override Task WriteRawAsync(string? json, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteRawAsync(json, cancellationToken) : base.WriteRawAsync(json, cancellationToken); } - internal Task DoWriteRawAsync(string json, CancellationToken cancellationToken) + internal Task DoWriteRawAsync(string? json, CancellationToken cancellationToken) { return _writer.WriteAsync(json, cancellationToken); } @@ -260,13 +291,13 @@ private Task WriteDigitsAsync(ulong uvalue, bool negative, CancellationToken can } int length = WriteNumberToBuffer(uvalue, negative); - return _writer.WriteAsync(_writeBuffer, 0, length, cancellationToken); + return _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken); } private Task WriteIntegerValueAsync(ulong uvalue, bool negative, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.Integer, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteDigitsAsync(uvalue, negative, cancellationToken); } @@ -298,7 +329,7 @@ internal Task WriteIntegerValueAsync(ulong uvalue, CancellationToken cancellatio private Task WriteEscapedStringAsync(string value, bool quote, CancellationToken cancellationToken) { - return JavaScriptUtils.WriteEscapedJavaScriptStringAsync(_writer, value, _quoteChar, quote, _charEscapeFlags, StringEscapeHandling, this, _writeBuffer, cancellationToken); + return JavaScriptUtils.WriteEscapedJavaScriptStringAsync(_writer, value, _quoteChar, quote, _charEscapeFlags!, StringEscapeHandling, this, _writeBuffer!, cancellationToken); } /// @@ -317,13 +348,13 @@ public override Task WritePropertyNameAsync(string name, CancellationToken cance internal Task DoWritePropertyNameAsync(string name, CancellationToken cancellationToken) { Task task = InternalWritePropertyNameAsync(name, cancellationToken); - if (!task.IsCompletedSucessfully()) + if (!task.IsCompletedSuccessfully()) { return DoWritePropertyNameAsync(task, name, cancellationToken); } task = WriteEscapedStringAsync(name, _quoteName, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync(':', cancellationToken); } @@ -395,7 +426,7 @@ public override Task WriteStartArrayAsync(CancellationToken cancellationToken = internal Task DoWriteStartArrayAsync(CancellationToken cancellationToken) { Task task = InternalWriteStartAsync(JsonToken.StartArray, JsonContainerType.Array, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync('[', cancellationToken); } @@ -425,7 +456,7 @@ public override Task WriteStartObjectAsync(CancellationToken cancellationToken = internal Task DoWriteStartObjectAsync(CancellationToken cancellationToken) { Task task = InternalWriteStartAsync(JsonToken.StartObject, JsonContainerType.Object, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync('{', cancellationToken); } @@ -477,7 +508,7 @@ public override Task WriteUndefinedAsync(CancellationToken cancellationToken = d internal Task DoWriteUndefinedAsync(CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.Undefined, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return _writer.WriteAsync(JsonConvert.Undefined, cancellationToken); } @@ -585,7 +616,7 @@ internal Task DoWriteValueAsync(byte? value, CancellationToken cancellationToken /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(byte[] value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(byte[]? value, CancellationToken cancellationToken = default) { return _safeAsync ? (value == null ? WriteNullAsync(cancellationToken) : WriteValueNonNullAsync(value, cancellationToken)) : base.WriteValueAsync(value, cancellationToken); } @@ -653,11 +684,11 @@ internal async Task DoWriteValueAsync(DateTime value, CancellationToken cancella await InternalWriteValueAsync(JsonToken.Date, cancellationToken).ConfigureAwait(false); value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); - await _writer.WriteAsync(_writeBuffer, 0, length, cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken).ConfigureAwait(false); } else { @@ -702,11 +733,11 @@ internal async Task DoWriteValueAsync(DateTimeOffset value, CancellationToken ca { await InternalWriteValueAsync(JsonToken.Date, cancellationToken).ConfigureAwait(false); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); - await _writer.WriteAsync(_writeBuffer, 0, length, cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(_writeBuffer!, 0, length, cancellationToken).ConfigureAwait(false); } else { @@ -953,7 +984,7 @@ internal Task WriteValueAsync(BigInteger value, CancellationToken cancellationTo /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(object value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(object? value, CancellationToken cancellationToken = default) { if (_safeAsync) { @@ -1046,15 +1077,15 @@ internal Task DoWriteValueAsync(short? value, CancellationToken cancellationToke /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(string value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(string? value, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteValueAsync(value, cancellationToken) : base.WriteValueAsync(value, cancellationToken); } - internal Task DoWriteValueAsync(string value, CancellationToken cancellationToken) + internal Task DoWriteValueAsync(string? value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken); } @@ -1062,7 +1093,7 @@ internal Task DoWriteValueAsync(string value, CancellationToken cancellationToke return DoWriteValueAsync(task, value, cancellationToken); } - private async Task DoWriteValueAsync(Task task, string value, CancellationToken cancellationToken) + private async Task DoWriteValueAsync(Task task, string? value, CancellationToken cancellationToken) { await task.ConfigureAwait(false); await (value == null ? _writer.WriteAsync(JsonConvert.Null, cancellationToken) : WriteEscapedStringAsync(value, true, cancellationToken)).ConfigureAwait(false); @@ -1181,7 +1212,7 @@ internal Task DoWriteValueAsync(ulong? value, CancellationToken cancellationToke /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteValueAsync(Uri value, CancellationToken cancellationToken = default) + public override Task WriteValueAsync(Uri? value, CancellationToken cancellationToken = default) { return _safeAsync ? (value == null ? WriteNullAsync(cancellationToken) : WriteValueNotNullAsync(value, cancellationToken)) : base.WriteValueAsync(value, cancellationToken); } @@ -1189,7 +1220,7 @@ public override Task WriteValueAsync(Uri value, CancellationToken cancellationTo internal Task WriteValueNotNullAsync(Uri value, CancellationToken cancellationToken) { Task task = InternalWriteValueAsync(JsonToken.String, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteEscapedStringAsync(value.OriginalString, true, cancellationToken); } @@ -1244,16 +1275,16 @@ internal Task DoWriteValueAsync(ushort? value, CancellationToken cancellationTok /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteCommentAsync(string text, CancellationToken cancellationToken = default) + public override Task WriteCommentAsync(string? text, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteCommentAsync(text, cancellationToken) : base.WriteCommentAsync(text, cancellationToken); } - internal async Task DoWriteCommentAsync(string text, CancellationToken cancellationToken) + internal async Task DoWriteCommentAsync(string? text, CancellationToken cancellationToken) { await InternalWriteCommentAsync(cancellationToken).ConfigureAwait(false); await _writer.WriteAsync("/*", cancellationToken).ConfigureAwait(false); - await _writer.WriteAsync(text, cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(text ?? string.Empty, cancellationToken).ConfigureAwait(false); await _writer.WriteAsync("*/", cancellationToken).ConfigureAwait(false); } @@ -1301,16 +1332,16 @@ public override Task WriteEndObjectAsync(CancellationToken cancellationToken = d /// A that represents the asynchronous operation. /// Derived classes must override this method to get asynchronous behaviour. Otherwise it will /// execute synchronously, returning an already-completed task. - public override Task WriteRawValueAsync(string json, CancellationToken cancellationToken = default) + public override Task WriteRawValueAsync(string? json, CancellationToken cancellationToken = default) { return _safeAsync ? DoWriteRawValueAsync(json, cancellationToken) : base.WriteRawValueAsync(json, cancellationToken); } - internal Task DoWriteRawValueAsync(string json, CancellationToken cancellationToken) + internal Task DoWriteRawValueAsync(string? json, CancellationToken cancellationToken) { UpdateScopeWithFinishedValue(); Task task = AutoCompleteAsync(JsonToken.Undefined, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteRawAsync(json, cancellationToken); } @@ -1318,7 +1349,7 @@ internal Task DoWriteRawValueAsync(string json, CancellationToken cancellationTo return DoWriteRawValueAsync(task, json, cancellationToken); } - private async Task DoWriteRawValueAsync(Task task, string json, CancellationToken cancellationToken) + private async Task DoWriteRawValueAsync(Task task, string? json, CancellationToken cancellationToken) { await task.ConfigureAwait(false); await WriteRawAsync(json, cancellationToken).ConfigureAwait(false); @@ -1331,7 +1362,7 @@ internal char[] EnsureWriteBuffer(int length, int copyTo) length = 35; } - char[] buffer = _writeBuffer; + char[]? buffer = _writeBuffer; if (buffer == null) { return _writeBuffer = BufferUtils.RentBuffer(_arrayPool, length); diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index 6b7abd91d..888bb04d1 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -33,6 +33,7 @@ using System.IO; using System.Xml; using Newtonsoft.Json.Utilities; +using System.Diagnostics; namespace Newtonsoft.Json { @@ -43,15 +44,15 @@ public partial class JsonTextWriter : JsonWriter { private const int IndentCharBufferSize = 12; private readonly TextWriter _writer; - private Base64Encoder _base64Encoder; + private Base64Encoder? _base64Encoder; private char _indentChar; private int _indentation; private char _quoteChar; private bool _quoteName; - private bool[] _charEscapeFlags; - private char[] _writeBuffer; - private IArrayPool _arrayPool; - private char[] _indentChars; + private bool[]? _charEscapeFlags; + private char[]? _writeBuffer; + private IArrayPool? _arrayPool; + private char[]? _indentChars; private Base64Encoder Base64Encoder { @@ -69,7 +70,7 @@ private Base64Encoder Base64Encoder /// /// Gets or sets the writer's character array pool. /// - public IArrayPool ArrayPool + public IArrayPool? ArrayPool { get => _arrayPool; set @@ -324,6 +325,7 @@ protected override void WriteIndent() int newLineLen = SetIndentChars(); + MiscellaneousUtils.Assert(_indentChars != null); _writer.Write(_indentChars, 0, newLineLen + Math.Min(currentIndentCount, IndentCharBufferSize)); while ((currentIndentCount -= IndentCharBufferSize) > 0) @@ -342,7 +344,7 @@ private int SetIndentChars() { for (int i = 0; i != newLineLen; ++i) { - if (writerNewLine[i] != _indentChars[i]) + if (writerNewLine[i] != _indentChars![i]) { match = false; break; @@ -387,7 +389,7 @@ private void WriteValueInternal(string value, JsonToken token) /// An error will raised if the value cannot be written as a single JSON token. /// /// The value to write. - public override void WriteValue(object value) + public override void WriteValue(object? value) { #if HAVE_BIG_INTEGER if (value is BigInteger i) @@ -424,7 +426,7 @@ public override void WriteUndefined() /// Writes raw JSON. /// /// The raw JSON to write. - public override void WriteRaw(string json) + public override void WriteRaw(string? json) { InternalWriteRaw(); @@ -435,7 +437,7 @@ public override void WriteRaw(string json) /// Writes a value. /// /// The value to write. - public override void WriteValue(string value) + public override void WriteValue(string? value) { InternalWriteValue(JsonToken.String); @@ -452,7 +454,7 @@ public override void WriteValue(string value) private void WriteEscapedString(string value, bool quote) { EnsureWriteBuffer(); - JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, quote, _charEscapeFlags, StringEscapeHandling, _arrayPool, ref _writeBuffer); + JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, quote, _charEscapeFlags!, StringEscapeHandling, _arrayPool, ref _writeBuffer); } /// @@ -632,10 +634,11 @@ public override void WriteValue(DateTime value) InternalWriteValue(JsonToken.Date); value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } else @@ -649,6 +652,7 @@ public override void WriteValue(DateTime value) private int WriteValueToBuffer(DateTime value) { EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int pos = 0; _writeBuffer[pos++] = _quoteChar; @@ -661,7 +665,7 @@ private int WriteValueToBuffer(DateTime value) /// Writes a [] value. /// /// The [] value to write. - public override void WriteValue(byte[] value) + public override void WriteValue(byte[]? value) { if (value == null) { @@ -686,10 +690,11 @@ public override void WriteValue(DateTimeOffset value) { InternalWriteValue(JsonToken.Date); - if (string.IsNullOrEmpty(DateFormatString)) + if (StringUtils.IsNullOrEmpty(DateFormatString)) { int length = WriteValueToBuffer(value); + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } else @@ -703,6 +708,7 @@ public override void WriteValue(DateTimeOffset value) private int WriteValueToBuffer(DateTimeOffset value) { EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int pos = 0; _writeBuffer[pos++] = _quoteChar; @@ -720,7 +726,7 @@ public override void WriteValue(Guid value) { InternalWriteValue(JsonToken.String); - string text = null; + string text; #if HAVE_CHAR_TO_STRING_WITH_CULTURE text = value.ToString("D", CultureInfo.InvariantCulture); @@ -757,7 +763,7 @@ public override void WriteValue(TimeSpan value) /// Writes a value. /// /// The value to write. - public override void WriteValue(Uri value) + public override void WriteValue(Uri? value) { if (value == null) { @@ -775,7 +781,7 @@ public override void WriteValue(Uri value) /// Writes a comment /*...*/ containing the specified text. /// /// Text to place inside the comment. - public override void WriteComment(string text) + public override void WriteComment(string? text) { InternalWriteComment(); @@ -826,6 +832,8 @@ private void WriteIntegerValue(ulong value, bool negative) else { int length = WriteNumberToBuffer(value, negative); + + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } } @@ -839,6 +847,7 @@ private int WriteNumberToBuffer(ulong value, bool negative) } EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int totalLength = MathUtils.IntLength(value); @@ -883,6 +892,8 @@ private void WriteIntegerValue(uint value, bool negative) else { int length = WriteNumberToBuffer(value, negative); + + MiscellaneousUtils.Assert(_writeBuffer != null); _writer.Write(_writeBuffer, 0, length); } } @@ -890,6 +901,7 @@ private void WriteIntegerValue(uint value, bool negative) private int WriteNumberToBuffer(uint value, bool negative) { EnsureWriteBuffer(); + MiscellaneousUtils.Assert(_writeBuffer != null); int totalLength = MathUtils.IntLength(value); diff --git a/Src/Newtonsoft.Json/JsonValidatingReader.cs b/Src/Newtonsoft.Json/JsonValidatingReader.cs index 34cc3ae6f..7b6de5902 100644 --- a/Src/Newtonsoft.Json/JsonValidatingReader.cs +++ b/Src/Newtonsoft.Json/JsonValidatingReader.cs @@ -41,6 +41,8 @@ #endif +#nullable disable + namespace Newtonsoft.Json { /// diff --git a/Src/Newtonsoft.Json/JsonWriter.Async.cs b/Src/Newtonsoft.Json/JsonWriter.Async.cs index 4a9c0f7d6..ffb1af826 100644 --- a/Src/Newtonsoft.Json/JsonWriter.Async.cs +++ b/Src/Newtonsoft.Json/JsonWriter.Async.cs @@ -37,7 +37,20 @@ namespace Newtonsoft.Json { public abstract partial class JsonWriter +#if HAVE_ASYNC_DISPOSABLE + : IAsyncDisposable +#endif { +#if HAVE_ASYNC_DISPOSABLE + async ValueTask IAsyncDisposable.DisposeAsync() + { + if (_currentState != State.Closed) + { + await CloseAsync().ConfigureAwait(false); + } + } +#endif + internal Task AutoCompleteAsync(JsonToken tokenBeingWritten, CancellationToken cancellationToken) { State oldState = _currentState; @@ -225,7 +238,7 @@ protected virtual Task WriteIndentSpaceAsync(CancellationToken cancellationToken /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteRawAsync(string json, CancellationToken cancellationToken = default) + public virtual Task WriteRawAsync(string? json, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -291,7 +304,7 @@ internal Task InternalWriteEndAsync(JsonContainerType type, CancellationToken ca if (_currentState == State.Property) { t = WriteNullAsync(cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitProperty(t, levelsToComplete, token, cancellationToken); } @@ -302,7 +315,7 @@ internal Task InternalWriteEndAsync(JsonContainerType type, CancellationToken ca if (_currentState != State.ObjectStart && _currentState != State.ArrayStart) { t = WriteIndentAsync(cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitIndent(t, levelsToComplete, token, cancellationToken); } @@ -310,7 +323,7 @@ internal Task InternalWriteEndAsync(JsonContainerType type, CancellationToken ca } t = WriteEndAsync(token, cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitEnd(t, levelsToComplete, cancellationToken); } @@ -546,7 +559,7 @@ internal async Task InternalWriteStartAsync(JsonToken token, JsonContainerType c /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteCommentAsync(string text, CancellationToken cancellationToken = default) + public virtual Task WriteCommentAsync(string? text, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -570,7 +583,7 @@ internal Task InternalWriteCommentAsync(CancellationToken cancellationToken) /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteRawValueAsync(string json, CancellationToken cancellationToken = default) + public virtual Task WriteRawValueAsync(string? json, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -673,7 +686,7 @@ public Task WriteTokenAsync(JsonToken token, CancellationToken cancellationToken /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public Task WriteTokenAsync(JsonToken token, object value, CancellationToken cancellationToken = default) + public Task WriteTokenAsync(JsonToken token, object? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -691,10 +704,10 @@ public Task WriteTokenAsync(JsonToken token, object value, CancellationToken can return WriteStartArrayAsync(cancellationToken); case JsonToken.StartConstructor: ValidationUtils.ArgumentNotNull(value, nameof(value)); - return WriteStartConstructorAsync(value.ToString(), cancellationToken); + return WriteStartConstructorAsync(value.ToString()!, cancellationToken); case JsonToken.PropertyName: ValidationUtils.ArgumentNotNull(value, nameof(value)); - return WritePropertyNameAsync(value.ToString(), cancellationToken); + return WritePropertyNameAsync(value.ToString()!, cancellationToken); case JsonToken.Comment: return WriteCommentAsync(value?.ToString(), cancellationToken); case JsonToken.Integer: @@ -755,7 +768,7 @@ public Task WriteTokenAsync(JsonToken token, object value, CancellationToken can return WriteValueAsync(guid, cancellationToken); } - return WriteValueAsync((byte[])value, cancellationToken); + return WriteValueAsync((byte[]?)value, cancellationToken); default: throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(token), token, "Unexpected token type."); } @@ -768,7 +781,7 @@ internal virtual async Task WriteTokenAsync(JsonReader reader, bool writeChildre do { // write a JValue date when the constructor is for a date - if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { await WriteConstructorDateAsync(reader, cancellationToken).ConfigureAwait(false); } @@ -785,7 +798,7 @@ internal virtual async Task WriteTokenAsync(JsonReader reader, bool writeChildre && writeChildren && await reader.ReadAsync(cancellationToken).ConfigureAwait(false)); - if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth)) { throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); } @@ -801,7 +814,7 @@ internal async Task WriteTokenSyncReadingAsync(JsonReader reader, CancellationTo do { // write a JValue date when the constructor is for a date - if (reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { WriteConstructorDate(reader); } @@ -831,7 +844,7 @@ private async Task WriteConstructorDateAsync(JsonReader reader, CancellationToke throw JsonWriterException.Create(this, "Unexpected token when reading date constructor. Expected Integer, got " + reader.TokenType, null); } - DateTime date = DateTimeUtils.ConvertJavaScriptTicksToDateTime((long)reader.Value); + DateTime date = DateTimeUtils.ConvertJavaScriptTicksToDateTime((long)reader.Value!); if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { @@ -929,7 +942,7 @@ public virtual Task WriteValueAsync(byte? value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(byte[] value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(byte[]? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -1290,7 +1303,7 @@ public virtual Task WriteValueAsync(long? value, CancellationToken cancellationT /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(object value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(object? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -1387,7 +1400,7 @@ public virtual Task WriteValueAsync(short? value, CancellationToken cancellation /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(string value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(string? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -1524,7 +1537,7 @@ public virtual Task WriteValueAsync(ulong? value, CancellationToken cancellation /// A that represents the asynchronous operation. /// The default behaviour is to execute synchronously, returning an already-completed task. Derived /// classes can override this behaviour for true asynchronicity. - public virtual Task WriteValueAsync(Uri value, CancellationToken cancellationToken = default) + public virtual Task WriteValueAsync(Uri? value, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index c253585b5..5fd5efe40 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -62,7 +62,7 @@ internal enum State // array that gives a new state based on the current state an the token being written private static readonly State[][] StateArray; - internal static readonly State[][] StateArrayTempate = new[] + internal static readonly State[][] StateArrayTemplate = new[] { // Start PropertyName ObjectStart Object ArrayStart Array ConstructorStart Constructor Closed Error // @@ -78,9 +78,9 @@ internal enum State internal static State[][] BuildStateArray() { - List allStates = StateArrayTempate.ToList(); - State[] errorStates = StateArrayTempate[0]; - State[] valueStates = StateArrayTempate[7]; + List allStates = StateArrayTemplate.ToList(); + State[] errorStates = StateArrayTemplate[0]; + State[] valueStates = StateArrayTemplate[7]; EnumInfo enumValuesAndNames = EnumUtils.GetEnumValuesAndNames(typeof(JsonToken)); @@ -116,7 +116,7 @@ static JsonWriter() StateArray = BuildStateArray(); } - private List _stack; + private List? _stack; private JsonPosition _currentPosition; private State _currentState; private Formatting _formatting; @@ -218,7 +218,7 @@ public string Path JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null; - return JsonPosition.BuildPath(_stack, current); + return JsonPosition.BuildPath(_stack!, current); } } @@ -226,8 +226,8 @@ public string Path private DateTimeZoneHandling _dateTimeZoneHandling; private StringEscapeHandling _stringEscapeHandling; private FloatFormatHandling _floatFormatHandling; - private string _dateFormatString; - private CultureInfo _culture; + private string? _dateFormatString; + private CultureInfo? _culture; /// /// Gets or sets a value indicating how JSON text output should be formatted. @@ -325,7 +325,7 @@ public FloatFormatHandling FloatFormatHandling /// /// Gets or sets how and values are formatted when writing JSON text. /// - public string DateFormatString + public string? DateFormatString { get => _dateFormatString; set => _dateFormatString = value; @@ -522,7 +522,7 @@ public void WriteToken(JsonReader reader, bool writeChildren) /// A value is only required for tokens that have an associated value, e.g. the property name for . /// null can be passed to the method for tokens that don't have a value, e.g. . /// - public void WriteToken(JsonToken token, object value) + public void WriteToken(JsonToken token, object? value) { switch (token) { @@ -537,11 +537,11 @@ public void WriteToken(JsonToken token, object value) break; case JsonToken.StartConstructor: ValidationUtils.ArgumentNotNull(value, nameof(value)); - WriteStartConstructor(value.ToString()); + WriteStartConstructor(value.ToString()!); break; case JsonToken.PropertyName: ValidationUtils.ArgumentNotNull(value, nameof(value)); - WritePropertyName(value.ToString()); + WritePropertyName(value.ToString()!); break; case JsonToken.Comment: WriteComment(value?.ToString()); @@ -579,8 +579,9 @@ public void WriteToken(JsonToken token, object value) } break; case JsonToken.String: - ValidationUtils.ArgumentNotNull(value, nameof(value)); - WriteValue(value.ToString()); + // Allow for a null string. This matches JTokenReader behavior which can read + // a JsonToken.String with a null value. + WriteValue(value?.ToString()); break; case JsonToken.Boolean: ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -625,7 +626,7 @@ public void WriteToken(JsonToken token, object value) } else { - WriteValue((byte[])value); + WriteValue((byte[])value!); } break; default: @@ -649,7 +650,7 @@ internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool wri do { // write a JValue date when the constructor is for a date - if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal)) + if (writeDateConstructorAsDate && reader.TokenType == JsonToken.StartConstructor && string.Equals(reader.Value?.ToString(), "Date", StringComparison.Ordinal)) { WriteConstructorDate(reader); } @@ -666,12 +667,19 @@ internal virtual void WriteToken(JsonReader reader, bool writeChildren, bool wri && writeChildren && reader.Read()); - if (initialDepth < CalculateWriteTokenFinalDepth(reader)) + if (IsWriteTokenIncomplete(reader, writeChildren, initialDepth)) { throw JsonWriterException.Create(this, "Unexpected end when reading token.", null); } } + private bool IsWriteTokenIncomplete(JsonReader reader, bool writeChildren, int initialDepth) + { + int finalDepth = CalculateWriteTokenFinalDepth(reader); + return initialDepth < finalDepth || + (writeChildren && initialDepth == finalDepth && JsonTokenUtils.IsStartToken(reader.TokenType)); + } + private int CalculateWriteTokenInitialDepth(JsonReader reader) { JsonToken type = reader.TokenType; @@ -696,7 +704,7 @@ private int CalculateWriteTokenFinalDepth(JsonReader reader) private void WriteConstructorDate(JsonReader reader) { - if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime dateTime, out string errorMessage)) + if (!JavaScriptUtils.TryGetDateFromConstructorJson(reader, out DateTime dateTime, out string? errorMessage)) { throw JsonWriterException.Create(this, errorMessage, null); } @@ -787,7 +795,7 @@ private int CalculateLevelsToComplete(JsonContainerType type) { int currentLevel = top - i; - if (_stack[currentLevel].Type == type) + if (_stack![currentLevel].Type == type) { levelsToComplete = i + 2; break; @@ -909,7 +917,7 @@ public virtual void WriteUndefined() /// Writes raw JSON without changing the writer's state. /// /// The raw JSON to write. - public virtual void WriteRaw(string json) + public virtual void WriteRaw(string? json) { InternalWriteRaw(); } @@ -918,7 +926,7 @@ public virtual void WriteRaw(string json) /// Writes raw JSON where a value is expected and updates the writer's state. /// /// The raw JSON to write. - public virtual void WriteRawValue(string json) + public virtual void WriteRawValue(string? json) { // hack. want writer to change state as if a value had been written UpdateScopeWithFinishedValue(); @@ -930,7 +938,7 @@ public virtual void WriteRawValue(string json) /// Writes a value. /// /// The value to write. - public virtual void WriteValue(string value) + public virtual void WriteValue(string? value) { InternalWriteValue(JsonToken.String); } @@ -1376,7 +1384,7 @@ public virtual void WriteValue(TimeSpan? value) /// Writes a [] value. /// /// The [] value to write. - public virtual void WriteValue(byte[] value) + public virtual void WriteValue(byte[]? value) { if (value == null) { @@ -1392,7 +1400,7 @@ public virtual void WriteValue(byte[] value) /// Writes a value. /// /// The value to write. - public virtual void WriteValue(Uri value) + public virtual void WriteValue(Uri? value) { if (value == null) { @@ -1409,7 +1417,7 @@ public virtual void WriteValue(Uri value) /// An error will raised if the value cannot be written as a single JSON token. /// /// The value to write. - public virtual void WriteValue(object value) + public virtual void WriteValue(object? value) { if (value == null) { @@ -1435,7 +1443,7 @@ public virtual void WriteValue(object value) /// Writes a comment /*...*/ containing the specified text. /// /// Text to place inside the comment. - public virtual void WriteComment(string text) + public virtual void WriteComment(string? text) { InternalWriteComment(); } diff --git a/Src/Newtonsoft.Json/JsonWriterException.cs b/Src/Newtonsoft.Json/JsonWriterException.cs index 4312b6bac..cb5b9ac7c 100644 --- a/Src/Newtonsoft.Json/JsonWriterException.cs +++ b/Src/Newtonsoft.Json/JsonWriterException.cs @@ -42,7 +42,7 @@ public class JsonWriterException : JsonException /// Gets the path to the JSON where the error occurred. /// /// The path to the JSON where the error occurred. - public string Path { get; } + public string? Path { get; } /// /// Initializes a new instance of the class. @@ -93,18 +93,18 @@ public JsonWriterException(SerializationInfo info, StreamingContext context) /// The error message that explains the reason for the exception. /// The path to the JSON where the error occurred. /// The exception that is the cause of the current exception, or null if no inner exception is specified. - public JsonWriterException(string message, string path, Exception innerException) + public JsonWriterException(string message, string path, Exception? innerException) : base(message, innerException) { Path = path; } - internal static JsonWriterException Create(JsonWriter writer, string message, Exception ex) + internal static JsonWriterException Create(JsonWriter writer, string message, Exception? ex) { return Create(writer.ContainerPath, message, ex); } - internal static JsonWriterException Create(string path, string message, Exception ex) + internal static JsonWriterException Create(string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(null, path, message); diff --git a/Src/Newtonsoft.Json/Linq/Extensions.cs b/Src/Newtonsoft.Json/Linq/Extensions.cs index 43b70d4bc..cd333a2f7 100644 --- a/Src/Newtonsoft.Json/Linq/Extensions.cs +++ b/Src/Newtonsoft.Json/Linq/Extensions.cs @@ -27,6 +27,8 @@ using System.Collections.Generic; using Newtonsoft.Json.Utilities; using System.Globalization; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -111,9 +113,9 @@ public static IJEnumerable Properties(this IEnumerable sourc /// An of that contains the source collection. /// The token key. /// An of that contains the values of every token in the source collection with the given key. - public static IJEnumerable Values(this IEnumerable source, object key) + public static IJEnumerable Values(this IEnumerable source, object? key) { - return Values(source, key).AsJEnumerable(); + return Values(source, key)!.AsJEnumerable(); } /// @@ -133,7 +135,7 @@ public static IJEnumerable Values(this IEnumerable source) /// An of that contains the source collection. /// The token key. /// An that contains the converted values of every token in the source collection with the given key. - public static IEnumerable Values(this IEnumerable source, object key) + public static IEnumerable Values(this IEnumerable source, object key) { return Values(source, key); } @@ -144,7 +146,7 @@ public static IEnumerable Values(this IEnumerable source, object k /// The type to convert the values to. /// An of that contains the source collection. /// An that contains the converted values of every token in the source collection. - public static IEnumerable Values(this IEnumerable source) + public static IEnumerable Values(this IEnumerable source) { return Values(source, null); } @@ -155,7 +157,7 @@ public static IEnumerable Values(this IEnumerable source) /// The type to convert the value to. /// A cast as a of . /// A converted value. - public static U Value(this IEnumerable value) + public static U? Value(this IEnumerable value) { return value.Value(); } @@ -167,7 +169,7 @@ public static U Value(this IEnumerable value) /// The type to convert the value to. /// A cast as a of . /// A converted value. - public static U Value(this IEnumerable value) where T : JToken + public static U? Value(this IEnumerable value) where T : JToken { ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -179,7 +181,7 @@ public static U Value(this IEnumerable value) where T : JToken return token.Convert(); } - internal static IEnumerable Values(this IEnumerable source, object key) where T : JToken + internal static IEnumerable Values(this IEnumerable source, object? key) where T : JToken { ValidationUtils.ArgumentNotNull(source, nameof(source)); @@ -204,7 +206,7 @@ internal static IEnumerable Values(this IEnumerable source, object k { foreach (T token in source) { - JToken value = token[key]; + JToken? value = token[key]; if (value != null) { yield return value.Convert(); @@ -224,7 +226,7 @@ internal static IEnumerable Values(this IEnumerable source, object k /// An of that contains the values of every token in the source collection. public static IJEnumerable Children(this IEnumerable source) where T : JToken { - return Children(source).AsJEnumerable(); + return Children(source)!.AsJEnumerable(); } /// @@ -234,14 +236,14 @@ public static IJEnumerable Children(this IEnumerable source) where /// The type to convert the values to. /// The source collection type. /// An that contains the converted values of every token in the source collection. - public static IEnumerable Children(this IEnumerable source) where T : JToken + public static IEnumerable Children(this IEnumerable source) where T : JToken { ValidationUtils.ArgumentNotNull(source, nameof(source)); return source.SelectMany(c => c.Children()).Convert(); } - internal static IEnumerable Convert(this IEnumerable source) where T : JToken + internal static IEnumerable Convert(this IEnumerable source) where T : JToken { ValidationUtils.ArgumentNotNull(source, nameof(source)); @@ -251,11 +253,13 @@ internal static IEnumerable Convert(this IEnumerable source) where T } } - internal static U Convert(this T token) where T : JToken + internal static U? Convert(this T token) where T : JToken? { if (token == null) { +#pragma warning disable CS8653 // A default expression introduces a null value for a type parameter. return default; +#pragma warning restore CS8653 // A default expression introduces a null value for a type parameter. } if (token is U castValue @@ -282,13 +286,15 @@ internal static U Convert(this T token) where T : JToken { if (value.Value == null) { +#pragma warning disable CS8653 // A default expression introduces a null value for a type parameter. return default; +#pragma warning restore CS8653 // A default expression introduces a null value for a type parameter. } - targetType = Nullable.GetUnderlyingType(targetType); + targetType = Nullable.GetUnderlyingType(targetType)!; } - return (U)System.Convert.ChangeType(value.Value, targetType, CultureInfo.InvariantCulture); + return (U?)System.Convert.ChangeType(value.Value, targetType, CultureInfo.InvariantCulture); } } @@ -315,7 +321,7 @@ public static IJEnumerable AsJEnumerable(this IEnumerable source) where { if (source == null) { - return null; + return null!; } else if (source is IJEnumerable customEnumerable) { diff --git a/Src/Newtonsoft.Json/Linq/JArray.Async.cs b/Src/Newtonsoft.Json/Linq/JArray.Async.cs index ef6bdf523..25ffe4efe 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.Async.cs @@ -73,7 +73,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can /// If this is null, default load settings will be used. /// The token to monitor for cancellation requests. The default value is . /// A representing the asynchronous load. The property contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { if (reader.TokenType == JsonToken.None) { diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs index 270027e84..c589e211b 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.cs @@ -66,7 +66,12 @@ public JArray() /// /// A object to copy from. public JArray(JArray other) - : base(other) + : base(other, settings: null) + { + } + + internal JArray(JArray other, JsonCloneSettings? settings) + : base(other, settings) { } @@ -93,9 +98,9 @@ internal override bool DeepEquals(JToken node) return (node is JArray t && ContentsEqual(t)); } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JArray(this); + return new JArray(this, settings); } /// @@ -115,7 +120,7 @@ internal override JToken CloneToken() /// The used to load the JSON. /// If this is null, default load settings will be used. /// A that contains the JSON that was read from the specified . - public new static JArray Load(JsonReader reader, JsonLoadSettings settings) + public new static JArray Load(JsonReader reader, JsonLoadSettings? settings) { if (reader.TokenType == JsonToken.None) { @@ -163,7 +168,7 @@ internal override JToken CloneToken() /// /// /// - public new static JArray Parse(string json, JsonLoadSettings settings) + public new static JArray Parse(string json, JsonLoadSettings? settings) { using (JsonReader reader = new JsonTextReader(new StringReader(json))) { @@ -227,7 +232,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter /// Gets the with the specified key. /// /// The with the specified key. - public override JToken this[object key] + public override JToken? this[object key] { get { @@ -263,14 +268,19 @@ public JToken this[int index] set => SetItem(index, value); } - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _values.IndexOfReference(item); } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { - IEnumerable a = (IsMultiContent(content) || content is JArray) + IEnumerable? a = (IsMultiContent(content) || content is JArray) ? (IEnumerable)content : null; if (a == null) @@ -304,7 +314,7 @@ public int IndexOf(JToken item) /// public void Insert(int index, JToken item) { - InsertItem(index, item, false); + InsertItem(index, item, false, copyAnnotations: true); } /// diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.Async.cs b/Src/Newtonsoft.Json/Linq/JConstructor.Async.cs index d24b81f82..bdbeff69a 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.Async.cs @@ -43,7 +43,7 @@ public partial class JConstructor /// A that represents the asynchronous write operation. public override async Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) { - await writer.WriteStartConstructorAsync(_name, cancellationToken).ConfigureAwait(false); + await writer.WriteStartConstructorAsync(_name ?? string.Empty, cancellationToken).ConfigureAwait(false); for (int i = 0; i < _values.Count; i++) { @@ -76,7 +76,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can /// /// A that represents the asynchronous load. The /// property returns a that contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { if (reader.TokenType == JsonToken.None) { @@ -93,7 +93,7 @@ public override async Task WriteToAsync(JsonWriter writer, CancellationToken can throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JConstructor c = new JConstructor((string)reader.Value); + JConstructor c = new JConstructor((string)reader.Value!); c.SetLineInfo(reader as IJsonLineInfo, settings); await c.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false); diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs index 759008fd6..703dbbc12 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs @@ -36,7 +36,7 @@ namespace Newtonsoft.Json.Linq /// public partial class JConstructor : JContainer { - private string _name; + private string? _name; private readonly List _values = new List(); /// @@ -45,12 +45,17 @@ public partial class JConstructor : JContainer /// The container's children tokens. protected override IList ChildrenTokens => _values; - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _values.IndexOfReference(item); } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { if (!(content is JConstructor c)) { @@ -68,7 +73,7 @@ internal override void MergeItem(object content, JsonMergeSettings settings) /// Gets or sets the name of this constructor. /// /// The constructor name. - public string Name + public string? Name { get => _name; set => _name = value; @@ -92,7 +97,13 @@ public JConstructor() /// /// A object to copy from. public JConstructor(JConstructor other) - : base(other) + : base(other, settings: null) + { + _name = other.Name; + } + + internal JConstructor(JConstructor other, JsonCloneSettings? settings) + : base(other, settings) { _name = other.Name; } @@ -142,9 +153,9 @@ internal override bool DeepEquals(JToken node) return (node is JConstructor c && _name == c.Name && ContentsEqual(c)); } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings = null) { - return new JConstructor(this); + return new JConstructor(this, settings); } /// @@ -154,7 +165,7 @@ internal override JToken CloneToken() /// A collection of which will be used when writing the token. public override void WriteTo(JsonWriter writer, params JsonConverter[] converters) { - writer.WriteStartConstructor(_name); + writer.WriteStartConstructor(_name!); int count = _values.Count; for (int i = 0; i < count; i++) @@ -169,7 +180,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter /// Gets the with the specified key. /// /// The with the specified key. - public override JToken this[object key] + public override JToken? this[object key] { get { @@ -197,7 +208,13 @@ public override JToken this[object key] internal override int GetDeepHashCode() { - return _name.GetHashCode() ^ ContentsHashCode(); + int hash; +#if HAVE_GETHASHCODE_STRING_COMPARISON + hash = _name?.GetHashCode(StringComparison.Ordinal) ?? 0; +#else + hash = _name?.GetHashCode() ?? 0; +#endif + return hash ^ ContentsHashCode(); } /// @@ -217,7 +234,7 @@ internal override int GetDeepHashCode() /// The used to load the JSON. /// If this is null, default load settings will be used. /// A that contains the JSON that was read from the specified . - public new static JConstructor Load(JsonReader reader, JsonLoadSettings settings) + public new static JConstructor Load(JsonReader reader, JsonLoadSettings? settings) { if (reader.TokenType == JsonToken.None) { @@ -234,7 +251,7 @@ internal override int GetDeepHashCode() throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JConstructor c = new JConstructor((string)reader.Value); + JConstructor c = new JConstructor((string)reader.Value!); c.SetLineInfo(reader as IJsonLineInfo, settings); c.ReadTokenFrom(reader, settings); diff --git a/Src/Newtonsoft.Json/Linq/JContainer.Async.cs b/Src/Newtonsoft.Json/Linq/JContainer.Async.cs index 7aee837cd..8c02b2953 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.Async.cs @@ -26,6 +26,7 @@ #if HAVE_ASYNC using System; +using System.Diagnostics; using System.Globalization; using System.Threading; using System.Threading.Tasks; @@ -35,7 +36,7 @@ namespace Newtonsoft.Json.Linq { public abstract partial class JContainer { - internal async Task ReadTokenFromAsync(JsonReader reader, JsonLoadSettings options, CancellationToken cancellationToken = default) + internal async Task ReadTokenFromAsync(JsonReader reader, JsonLoadSettings? options, CancellationToken cancellationToken = default) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); int startDepth = reader.Depth; @@ -53,11 +54,11 @@ internal async Task ReadTokenFromAsync(JsonReader reader, JsonLoadSettings optio } } - private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { - IJsonLineInfo lineInfo = reader as IJsonLineInfo; + IJsonLineInfo? lineInfo = reader as IJsonLineInfo; - JContainer parent = this; + JContainer? parent = this; do { @@ -71,6 +72,8 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett parent = parent.Parent; } + MiscellaneousUtils.Assert(parent != null); + switch (reader.TokenType) { case JsonToken.None: @@ -106,7 +109,7 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett parent = parent.Parent; break; case JsonToken.StartConstructor: - JConstructor constructor = new JConstructor(reader.Value.ToString()); + JConstructor constructor = new JConstructor(reader.Value!.ToString()!); constructor.SetLineInfo(lineInfo, settings); parent.Add(constructor); parent = constructor; @@ -132,7 +135,7 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett case JsonToken.Comment: if (settings != null && settings.CommentHandling == CommentHandling.Load) { - v = JValue.CreateComment(reader.Value.ToString()); + v = JValue.CreateComment(reader.Value!.ToString()); v.SetLineInfo(lineInfo, settings); parent.Add(v); } @@ -148,7 +151,7 @@ private async Task ReadContentFromAsync(JsonReader reader, JsonLoadSettings sett parent.Add(v); break; case JsonToken.PropertyName: - JProperty property = ReadProperty(reader, settings, lineInfo, parent); + JProperty? property = ReadProperty(reader, settings, lineInfo, parent); if (property != null) { parent = property; diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index 2ad8fa408..e19be3619 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -33,11 +33,13 @@ using System.Collections; using System.Globalization; using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Newtonsoft.Json.Linq @@ -55,8 +57,8 @@ namespace Newtonsoft.Json.Linq #endif { #if HAVE_COMPONENT_MODEL - internal ListChangedEventHandler _listChanged; - internal AddingNewEventHandler _addingNew; + internal ListChangedEventHandler? _listChanged; + internal AddingNewEventHandler? _addingNew; /// /// Occurs when the list changes or an item in the list changes. @@ -77,12 +79,12 @@ public event AddingNewEventHandler AddingNew } #endif #if HAVE_INOTIFY_COLLECTION_CHANGED - internal NotifyCollectionChangedEventHandler _collectionChanged; + internal NotifyCollectionChangedEventHandler? _collectionChanged; /// /// Occurs when the items list of the collection has changed, or the collection is reset. /// - public event NotifyCollectionChangedEventHandler CollectionChanged + public event NotifyCollectionChangedEventHandler? CollectionChanged { add { _collectionChanged += value; } remove { _collectionChanged -= value; } @@ -95,7 +97,7 @@ public event NotifyCollectionChangedEventHandler CollectionChanged /// The container's children tokens. protected abstract IList ChildrenTokens { get; } - private object _syncRoot; + private object? _syncRoot; #if (HAVE_COMPONENT_MODEL || HAVE_INOTIFY_COLLECTION_CHANGED) private bool _busy; #endif @@ -104,15 +106,22 @@ internal JContainer() { } - internal JContainer(JContainer other) + internal JContainer(JContainer other, JsonCloneSettings? settings) : this() { ValidationUtils.ArgumentNotNull(other, nameof(other)); + bool copyAnnotations = settings?.CopyAnnotations ?? true; + + if (copyAnnotations) + { + CopyAnnotations(this, other); + } + int i = 0; foreach (JToken child in other) { - AddInternal(i, child, false); + TryAddInternal(i, child, false, copyAnnotations); i++; } } @@ -148,7 +157,7 @@ protected virtual void OnAddingNew(AddingNewEventArgs e) /// The instance containing the event data. protected virtual void OnListChanged(ListChangedEventArgs e) { - ListChangedEventHandler handler = _listChanged; + ListChangedEventHandler? handler = _listChanged; if (handler != null) { @@ -171,7 +180,7 @@ protected virtual void OnListChanged(ListChangedEventArgs e) /// The instance containing the event data. protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - NotifyCollectionChangedEventHandler handler = _collectionChanged; + NotifyCollectionChangedEventHandler? handler = _collectionChanged; if (handler != null) { @@ -228,7 +237,7 @@ internal bool ContentsEqual(JContainer container) /// /// A containing the first child token of the . /// - public override JToken First + public override JToken? First { get { @@ -243,7 +252,7 @@ public override JToken First /// /// A containing the last child token of the . /// - public override JToken Last + public override JToken? Last { get { @@ -271,7 +280,7 @@ public override JEnumerable Children() /// /// A containing the child values of this , in document order. /// - public override IEnumerable Values() + public override IEnumerable Values() where T : default { return ChildrenTokens.Convert(); } @@ -314,12 +323,12 @@ internal IEnumerable GetDescendants(bool self) } } - internal bool IsMultiContent(object content) + internal bool IsMultiContent([NotNullWhen(true)]object? content) { return (content is IEnumerable && !(content is string) && !(content is JToken) && !(content is byte[])); } - internal JToken EnsureParentToken(JToken item, bool skipParentCheck) + internal JToken EnsureParentToken(JToken? item, bool skipParentCheck, bool copyAnnotations) { if (item == null) { @@ -337,15 +346,20 @@ internal JToken EnsureParentToken(JToken item, bool skipParentCheck) // the item is being added to the root parent of itself if (item.Parent != null || item == this || (item.HasValues && Root == item)) { - item = item.CloneToken(); + // Avoid allocating settings when copy annotations is false. + JsonCloneSettings? settings = copyAnnotations + ? null + : JsonCloneSettings.SkipCopyAnnotations; + + item = item.CloneToken(settings); } return item; } - internal abstract int IndexOfItem(JToken item); + internal abstract int IndexOfItem(JToken? item); - internal virtual void InsertItem(int index, JToken item, bool skipParentCheck) + internal virtual bool InsertItem(int index, JToken? item, bool skipParentCheck, bool copyAnnotations) { IList children = ChildrenTokens; @@ -356,11 +370,11 @@ internal virtual void InsertItem(int index, JToken item, bool skipParentCheck) CheckReentrancy(); - item = EnsureParentToken(item, skipParentCheck); + item = EnsureParentToken(item, skipParentCheck, copyAnnotations); - JToken previous = (index == 0) ? null : children[index - 1]; + JToken? previous = (index == 0) ? null : children[index - 1]; // haven't inserted new token yet so next token is still at the inserting index - JToken next = (index == children.Count) ? null : children[index]; + JToken? next = (index == children.Count) ? null : children[index]; ValidateToken(item, null); @@ -392,6 +406,8 @@ internal virtual void InsertItem(int index, JToken item, bool skipParentCheck) OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); } #endif + + return true; } internal virtual void RemoveItemAt(int index) @@ -410,8 +426,8 @@ internal virtual void RemoveItemAt(int index) CheckReentrancy(); JToken item = children[index]; - JToken previous = (index == 0) ? null : children[index - 1]; - JToken next = (index == children.Count - 1) ? null : children[index + 1]; + JToken? previous = (index == 0) ? null : children[index - 1]; + JToken? next = (index == children.Count - 1) ? null : children[index + 1]; if (previous != null) { @@ -442,13 +458,16 @@ internal virtual void RemoveItemAt(int index) #endif } - internal virtual bool RemoveItem(JToken item) + internal virtual bool RemoveItem(JToken? item) { - int index = IndexOfItem(item); - if (index >= 0) + if (item != null) { - RemoveItemAt(index); - return true; + int index = IndexOfItem(item); + if (index >= 0) + { + RemoveItemAt(index); + return true; + } } return false; @@ -459,7 +478,7 @@ internal virtual JToken GetItem(int index) return ChildrenTokens[index]; } - internal virtual void SetItem(int index, JToken item) + internal virtual void SetItem(int index, JToken? item) { IList children = ChildrenTokens; @@ -481,12 +500,12 @@ internal virtual void SetItem(int index, JToken item) CheckReentrancy(); - item = EnsureParentToken(item, false); + item = EnsureParentToken(item, false, copyAnnotations: true); ValidateToken(item, existing); - JToken previous = (index == 0) ? null : children[index - 1]; - JToken next = (index == children.Count - 1) ? null : children[index + 1]; + JToken? previous = (index == 0) ? null : children[index - 1]; + JToken? next = (index == children.Count - 1) ? null : children[index + 1]; item.Parent = this; @@ -562,7 +581,7 @@ internal virtual void ReplaceItem(JToken existing, JToken replacement) SetItem(index, replacement); } - internal virtual bool ContainsItem(JToken item) + internal virtual bool ContainsItem(JToken? item) { return (IndexOfItem(item) != -1); } @@ -594,14 +613,14 @@ internal virtual void CopyItemsTo(Array array, int arrayIndex) } } - internal static bool IsTokenUnchanged(JToken currentValue, JToken newValue) + internal static bool IsTokenUnchanged(JToken currentValue, JToken? newValue) { if (currentValue is JValue v1) { - // null will get turned into a JValue of type null - if (v1.Type == JTokenType.Null && newValue == null) + if (newValue == null) { - return true; + // null will get turned into a JValue of type null + return v1.Type == JTokenType.Null; } return v1.Equals(newValue); @@ -610,7 +629,7 @@ internal static bool IsTokenUnchanged(JToken currentValue, JToken newValue) return false; } - internal virtual void ValidateToken(JToken o, JToken existing) + internal virtual void ValidateToken(JToken o, JToken? existing) { ValidationUtils.ArgumentNotNull(o, nameof(o)); @@ -624,26 +643,31 @@ internal virtual void ValidateToken(JToken o, JToken existing) /// Adds the specified content as children of this . /// /// The content to be added. - public virtual void Add(object content) + public virtual void Add(object? content) + { + TryAddInternal(ChildrenTokens.Count, content, false, copyAnnotations: true); + } + + internal bool TryAdd(object? content) { - AddInternal(ChildrenTokens.Count, content, false); + return TryAddInternal(ChildrenTokens.Count, content, false, copyAnnotations: true); } internal void AddAndSkipParentCheck(JToken token) { - AddInternal(ChildrenTokens.Count, token, true); + TryAddInternal(ChildrenTokens.Count, token, true, copyAnnotations: true); } /// /// Adds the specified content as the first children of this . /// /// The content to be added. - public void AddFirst(object content) + public void AddFirst(object? content) { - AddInternal(0, content, false); + TryAddInternal(0, content, false, copyAnnotations: true); } - internal void AddInternal(int index, object content, bool skipParentCheck) + internal bool TryAddInternal(int index, object? content, bool skipParentCheck, bool copyAnnotations) { if (IsMultiContent(content)) { @@ -652,19 +676,21 @@ internal void AddInternal(int index, object content, bool skipParentCheck) int multiIndex = index; foreach (object c in enumerable) { - AddInternal(multiIndex, c, skipParentCheck); + TryAddInternal(multiIndex, c, skipParentCheck, copyAnnotations); multiIndex++; } + + return true; } else { JToken item = CreateFromContent(content); - InsertItem(index, item, skipParentCheck); + return InsertItem(index, item, skipParentCheck, copyAnnotations); } } - internal static JToken CreateFromContent(object content) + internal static JToken CreateFromContent(object? content) { if (content is JToken token) { @@ -701,15 +727,21 @@ public void RemoveAll() ClearItems(); } - internal abstract void MergeItem(object content, JsonMergeSettings settings); + internal abstract void MergeItem(object content, JsonMergeSettings? settings); /// /// Merge the specified content into this . /// /// The content to be merged. - public void Merge(object content) + public void Merge(object? content) { - MergeItem(content, new JsonMergeSettings()); + if (content == null) + { + return; + } + + ValidateContent(content); + MergeItem(content, null); } /// @@ -717,12 +749,32 @@ public void Merge(object content) /// /// The content to be merged. /// The used to merge the content. - public void Merge(object content, JsonMergeSettings settings) + public void Merge(object? content, JsonMergeSettings? settings) { + if (content == null) + { + return; + } + + ValidateContent(content); MergeItem(content, settings); } - internal void ReadTokenFrom(JsonReader reader, JsonLoadSettings options) + private void ValidateContent(object content) + { + if (content.GetType().IsSubclassOf(typeof(JToken))) + { + return; + } + if (IsMultiContent(content)) + { + return; + } + + throw new ArgumentException("Could not determine JSON object type for type {0}.".FormatWith(CultureInfo.InvariantCulture, content.GetType()), nameof(content)); + } + + internal void ReadTokenFrom(JsonReader reader, JsonLoadSettings? options) { int startDepth = reader.Depth; @@ -741,12 +793,12 @@ internal void ReadTokenFrom(JsonReader reader, JsonLoadSettings options) } } - internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) + internal void ReadContentFrom(JsonReader r, JsonLoadSettings? settings) { ValidationUtils.ArgumentNotNull(r, nameof(r)); - IJsonLineInfo lineInfo = r as IJsonLineInfo; + IJsonLineInfo? lineInfo = r as IJsonLineInfo; - JContainer parent = this; + JContainer? parent = this; do { @@ -760,6 +812,8 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) parent = parent.Parent; } + MiscellaneousUtils.Assert(parent != null); + switch (r.TokenType) { case JsonToken.None: @@ -795,7 +849,7 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) parent = parent.Parent; break; case JsonToken.StartConstructor: - JConstructor constructor = new JConstructor(r.Value.ToString()); + JConstructor constructor = new JConstructor(r.Value!.ToString()!); constructor.SetLineInfo(lineInfo, settings); parent.Add(constructor); parent = constructor; @@ -821,7 +875,7 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) case JsonToken.Comment: if (settings != null && settings.CommentHandling == CommentHandling.Load) { - v = JValue.CreateComment(r.Value.ToString()); + v = JValue.CreateComment(r.Value!.ToString()); v.SetLineInfo(lineInfo, settings); parent.Add(v); } @@ -837,7 +891,7 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) parent.Add(v); break; case JsonToken.PropertyName: - JProperty property = ReadProperty(r, settings, lineInfo, parent); + JProperty? property = ReadProperty(r, settings, lineInfo, parent); if (property != null) { parent = property; @@ -853,13 +907,13 @@ internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) } while (r.Read()); } - private static JProperty ReadProperty(JsonReader r, JsonLoadSettings settings, IJsonLineInfo lineInfo, JContainer parent) + private static JProperty? ReadProperty(JsonReader r, JsonLoadSettings? settings, IJsonLineInfo? lineInfo, JContainer parent) { DuplicatePropertyNameHandling duplicatePropertyNameHandling = settings?.DuplicatePropertyNameHandling ?? DuplicatePropertyNameHandling.Replace; JObject parentObject = (JObject)parent; - string propertyName = r.Value.ToString(); - JProperty existingPropertyWithName = parentObject.Property(propertyName, StringComparison.Ordinal); + string propertyName = r.Value!.ToString()!; + JProperty? existingPropertyWithName = parentObject.Property(propertyName, StringComparison.Ordinal); if (existingPropertyWithName != null) { if (duplicatePropertyNameHandling == DuplicatePropertyNameHandling.Ignore) @@ -905,8 +959,9 @@ string ITypedList.GetListName(PropertyDescriptor[] listAccessors) PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) { - ICustomTypeDescriptor d = First as ICustomTypeDescriptor; - return d?.GetProperties(); + ICustomTypeDescriptor? d = First as ICustomTypeDescriptor; + + return d?.GetProperties() ?? new PropertyDescriptorCollection(CollectionUtils.ArrayEmpty()); } #endif @@ -918,7 +973,7 @@ int IList.IndexOf(JToken item) void IList.Insert(int index, JToken item) { - InsertItem(index, item, false); + InsertItem(index, item, false, copyAnnotations: true); } void IList.RemoveAt(int index) @@ -962,7 +1017,7 @@ bool ICollection.Remove(JToken item) } #endregion - private JToken EnsureValue(object value) + private JToken? EnsureValue(object? value) { if (value == null) { @@ -978,7 +1033,7 @@ private JToken EnsureValue(object value) } #region IList Members - int IList.Add(object value) + int IList.Add(object? value) { Add(EnsureValue(value)); return Count - 1; @@ -989,26 +1044,26 @@ void IList.Clear() ClearItems(); } - bool IList.Contains(object value) + bool IList.Contains(object? value) { return ContainsItem(EnsureValue(value)); } - int IList.IndexOf(object value) + int IList.IndexOf(object? value) { return IndexOfItem(EnsureValue(value)); } - void IList.Insert(int index, object value) + void IList.Insert(int index, object? value) { - InsertItem(index, EnsureValue(value), false); + InsertItem(index, EnsureValue(value), false, copyAnnotations: false); } bool IList.IsFixedSize => false; bool IList.IsReadOnly => false; - void IList.Remove(object value) + void IList.Remove(object? value) { RemoveItem(EnsureValue(value)); } @@ -1018,7 +1073,7 @@ void IList.RemoveAt(int index) RemoveItemAt(index); } - object IList.this[int index] + object? IList.this[int index] { get => GetItem(index); set => SetItem(index, EnsureValue(value)); @@ -1108,7 +1163,7 @@ void IBindingList.RemoveSort() ListSortDirection IBindingList.SortDirection => ListSortDirection.Ascending; - PropertyDescriptor IBindingList.SortProperty => null; + PropertyDescriptor? IBindingList.SortProperty => null; bool IBindingList.SupportsChangeNotification => true; @@ -1118,25 +1173,27 @@ void IBindingList.RemoveSort() #endif #endregion - internal static void MergeEnumerableContent(JContainer target, IEnumerable content, JsonMergeSettings settings) + internal static void MergeEnumerableContent(JContainer target, IEnumerable content, JsonMergeSettings? settings) { - switch (settings.MergeArrayHandling) + switch (settings?.MergeArrayHandling ?? MergeArrayHandling.Concat) { case MergeArrayHandling.Concat: - foreach (JToken item in content) + foreach (object item in content) { - target.Add(item); + target.Add(CreateFromContent(item)); } break; case MergeArrayHandling.Union: #if HAVE_HASH_SET HashSet items = new HashSet(target, EqualityComparer); - foreach (JToken item in content) + foreach (object item in content) { - if (items.Add(item)) + JToken contentItem = CreateFromContent(item); + + if (items.Add(contentItem)) { - target.Add(item); + target.Add(contentItem); } } #else @@ -1146,21 +1203,27 @@ internal static void MergeEnumerableContent(JContainer target, IEnumerable conte items[t] = true; } - foreach (JToken item in content) + foreach (object item in content) { - if (!items.ContainsKey(item)) + JToken contentItem = CreateFromContent(item); + + if (!items.ContainsKey(contentItem)) { - items[item] = true; - target.Add(item); + items[contentItem] = true; + target.Add(contentItem); } } #endif break; case MergeArrayHandling.Replace: + if (target == content) + { + break; + } target.ClearItems(); - foreach (JToken item in content) + foreach (object item in content) { - target.Add(item); + target.Add(CreateFromContent(item)); } break; case MergeArrayHandling.Merge: @@ -1169,7 +1232,7 @@ internal static void MergeEnumerableContent(JContainer target, IEnumerable conte { if (i < target.Count) { - JToken sourceItem = target[i]; + JToken? sourceItem = target[i]; if (sourceItem is JContainer existingContainer) { @@ -1189,7 +1252,7 @@ internal static void MergeEnumerableContent(JContainer target, IEnumerable conte } else { - target.Add(targetItem); + target.Add(CreateFromContent(targetItem)); } i++; diff --git a/Src/Newtonsoft.Json/Linq/JEnumerable.cs b/Src/Newtonsoft.Json/Linq/JEnumerable.cs index 93bbe1a79..41de4c333 100644 --- a/Src/Newtonsoft.Json/Linq/JEnumerable.cs +++ b/Src/Newtonsoft.Json/Linq/JEnumerable.cs @@ -88,7 +88,7 @@ public IJEnumerable this[object key] return JEnumerable.Empty; } - return new JEnumerable(_enumerable.Values(key)); + return new JEnumerable(_enumerable.Values(key)!); } } @@ -111,7 +111,7 @@ public bool Equals(JEnumerable other) /// /// true if the specified is equal to this instance; otherwise, false. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is JEnumerable enumerable) { diff --git a/Src/Newtonsoft.Json/Linq/JObject.Async.cs b/Src/Newtonsoft.Json/Linq/JObject.Async.cs index 21eb02b76..67f01fe5f 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.Async.cs @@ -45,7 +45,7 @@ public partial class JObject public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) { Task t = writer.WriteStartObjectAsync(cancellationToken); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitProperties(t, 0, writer, cancellationToken, converters); } @@ -53,7 +53,7 @@ public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellat for (int i = 0; i < _properties.Count; i++) { t = _properties[i].WriteToAsync(writer, cancellationToken, converters); - if (!t.IsCompletedSucessfully()) + if (!t.IsCompletedSuccessfully()) { return AwaitProperties(t, i + 1, writer, cancellationToken, converters); } @@ -97,7 +97,7 @@ async Task AwaitProperties(Task task, int i, JsonWriter Writer, CancellationToke /// /// A that represents the asynchronous load. The /// property returns a that contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index 6ae7436df..fab460da4 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -37,6 +37,8 @@ using System.IO; using Newtonsoft.Json.Utilities; using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -51,7 +53,7 @@ namespace Newtonsoft.Json.Linq /// /// /// - public partial class JObject : JContainer, IDictionary, INotifyPropertyChanged + public partial class JObject : JContainer, IDictionary, INotifyPropertyChanged #if HAVE_COMPONENT_MODEL , ICustomTypeDescriptor #endif @@ -70,13 +72,13 @@ public partial class JObject : JContainer, IDictionary, INotifyP /// /// Occurs when a property value changes. /// - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; #if HAVE_INOTIFY_PROPERTY_CHANGING /// /// Occurs when a property value is changing. /// - public event PropertyChangingEventHandler PropertyChanging; + public event PropertyChangingEventHandler? PropertyChanging; #endif /// @@ -91,7 +93,12 @@ public JObject() /// /// A object to copy from. public JObject(JObject other) - : base(other) + : base(other, settings: null) + { + } + + internal JObject(JObject other, JsonCloneSettings? settings) + : base(other, settings) { } @@ -123,23 +130,28 @@ internal override bool DeepEquals(JToken node) return _properties.Compare(t._properties); } - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _properties.IndexOfReference(item); } - internal override void InsertItem(int index, JToken item, bool skipParentCheck) + internal override bool InsertItem(int index, JToken? item, bool skipParentCheck, bool copyAnnotations) { // don't add comments to JObject, no name to reference comment by if (item != null && item.Type == JTokenType.Comment) { - return; + return false; } - base.InsertItem(index, item, skipParentCheck); + return base.InsertItem(index, item, skipParentCheck, copyAnnotations); } - internal override void ValidateToken(JToken o, JToken existing) + internal override void ValidateToken(JToken o, JToken? existing) { ValidationUtils.ArgumentNotNull(o, nameof(o)); @@ -166,16 +178,16 @@ internal override void ValidateToken(JToken o, JToken existing) } } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { if (!(content is JObject o)) { return; } - foreach (KeyValuePair contentItem in o) + foreach (KeyValuePair contentItem in o) { - JProperty existingProperty = Property(contentItem.Key, settings?.PropertyNameComparison ?? StringComparison.Ordinal); + JProperty? existingProperty = Property(contentItem.Key, settings?.PropertyNameComparison ?? StringComparison.Ordinal); if (existingProperty == null) { @@ -237,9 +249,9 @@ internal void InternalPropertyChanging(JProperty childProperty) #endif } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings) { - return new JObject(this); + return new JObject(this, settings); } /// @@ -262,7 +274,7 @@ public IEnumerable Properties() /// /// The property name. /// A with the specified name or null. - public JProperty Property(string name) + public JProperty? Property(string name) { return Property(name, StringComparison.Ordinal); } @@ -275,14 +287,14 @@ public JProperty Property(string name) /// The property name. /// One of the enumeration values that specifies how the strings will be compared. /// A matched with the specified name or null. - public JProperty Property(string name, StringComparison comparison) + public JProperty? Property(string name, StringComparison comparison) { if (name == null) { return null; } - if (_properties.TryGetValue(name, out JToken property)) + if (_properties.TryGetValue(name, out JToken? property)) { return (JProperty)property; } @@ -316,7 +328,7 @@ public JEnumerable PropertyValues() /// Gets the with the specified key. /// /// The with the specified key. - public override JToken this[object key] + public override JToken? this[object key] { get { @@ -346,29 +358,29 @@ public override JToken this[object key] /// Gets or sets the with the specified property name. /// /// - public JToken this[string propertyName] + public JToken? this[string propertyName] { get { ValidationUtils.ArgumentNotNull(propertyName, nameof(propertyName)); - JProperty property = Property(propertyName, StringComparison.Ordinal); + JProperty? property = Property(propertyName, StringComparison.Ordinal); return property?.Value; } set { - JProperty property = Property(propertyName, StringComparison.Ordinal); + JProperty? property = Property(propertyName, StringComparison.Ordinal); if (property != null) { - property.Value = value; + property.Value = value!; } else { #if HAVE_INOTIFY_PROPERTY_CHANGING OnPropertyChanging(propertyName); #endif - Add(new JProperty(propertyName, value)); + Add(propertyName, value); OnPropertyChanged(propertyName); } } @@ -397,7 +409,7 @@ public JToken this[string propertyName] /// /// is not valid JSON. /// - public new static JObject Load(JsonReader reader, JsonLoadSettings settings) + public new static JObject Load(JsonReader reader, JsonLoadSettings? settings) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -453,7 +465,7 @@ public JToken this[string propertyName] /// /// /// - public new static JObject Parse(string json, JsonLoadSettings settings) + public new static JObject Parse(string json, JsonLoadSettings? settings) { using (JsonReader reader = new JsonTextReader(new StringReader(json))) { @@ -488,7 +500,7 @@ public JToken this[string propertyName] { JToken token = FromObjectInternal(o, jsonSerializer); - if (token != null && token.Type != JTokenType.Object) + if (token.Type != JTokenType.Object) { throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type)); } @@ -518,7 +530,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter /// /// Name of the property. /// The with the specified property name. - public JToken GetValue(string propertyName) + public JToken? GetValue(string? propertyName) { return GetValue(propertyName, StringComparison.Ordinal); } @@ -531,7 +543,7 @@ public JToken GetValue(string propertyName) /// Name of the property. /// One of the enumeration values that specifies how the strings will be compared. /// The with the specified property name. - public JToken GetValue(string propertyName, StringComparison comparison) + public JToken? GetValue(string? propertyName, StringComparison comparison) { if (propertyName == null) { @@ -553,7 +565,7 @@ public JToken GetValue(string propertyName, StringComparison comparison) /// The value. /// One of the enumeration values that specifies how the strings will be compared. /// true if a value was successfully retrieved; otherwise, false. - public bool TryGetValue(string propertyName, StringComparison comparison, out JToken value) + public bool TryGetValue(string propertyName, StringComparison comparison, [NotNullWhen(true)]out JToken? value) { value = GetValue(propertyName, comparison); return (value != null); @@ -565,7 +577,7 @@ public bool TryGetValue(string propertyName, StringComparison comparison, out JT /// /// Name of the property. /// The value. - public void Add(string propertyName, JToken value) + public void Add(string propertyName, JToken? value) { Add(new JProperty(propertyName, value)); } @@ -582,7 +594,7 @@ public bool ContainsKey(string propertyName) return _properties.Contains(propertyName); } - ICollection IDictionary.Keys => _properties.Keys; + ICollection IDictionary.Keys => _properties.Keys; /// /// Removes the property with the specified name. @@ -591,7 +603,7 @@ public bool ContainsKey(string propertyName) /// true if item was successfully removed; otherwise, false. public bool Remove(string propertyName) { - JProperty property = Property(propertyName, StringComparison.Ordinal); + JProperty? property = Property(propertyName, StringComparison.Ordinal); if (property == null) { return false; @@ -607,9 +619,9 @@ public bool Remove(string propertyName) /// Name of the property. /// The value. /// true if a value was successfully retrieved; otherwise, false. - public bool TryGetValue(string propertyName, out JToken value) + public bool TryGetValue(string propertyName, [NotNullWhen(true)]out JToken? value) { - JProperty property = Property(propertyName, StringComparison.Ordinal); + JProperty? property = Property(propertyName, StringComparison.Ordinal); if (property == null) { value = null; @@ -620,24 +632,24 @@ public bool TryGetValue(string propertyName, out JToken value) return true; } - ICollection IDictionary.Values => throw new NotImplementedException(); + ICollection IDictionary.Values => throw new NotImplementedException(); #endregion #region ICollection> Members - void ICollection>.Add(KeyValuePair item) + void ICollection>.Add(KeyValuePair item) { Add(new JProperty(item.Key, item.Value)); } - void ICollection>.Clear() + void ICollection>.Clear() { RemoveAll(); } - bool ICollection>.Contains(KeyValuePair item) + bool ICollection>.Contains(KeyValuePair item) { - JProperty property = Property(item.Key, StringComparison.Ordinal); + JProperty? property = Property(item.Key, StringComparison.Ordinal); if (property == null) { return false; @@ -646,7 +658,7 @@ bool ICollection>.Contains(KeyValuePair>.CopyTo(KeyValuePair[] array, int arrayIndex) + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) { @@ -668,16 +680,16 @@ void ICollection>.CopyTo(KeyValuePair(property.Name, property.Value); + array[arrayIndex + index] = new KeyValuePair(property.Name, property.Value); index++; } } - bool ICollection>.IsReadOnly => false; + bool ICollection>.IsReadOnly => false; - bool ICollection>.Remove(KeyValuePair item) + bool ICollection>.Remove(KeyValuePair item) { - if (!((ICollection>)this).Contains(item)) + if (!((ICollection>)this).Contains(item)) { return false; } @@ -698,11 +710,11 @@ internal override int GetDeepHashCode() /// /// A that can be used to iterate through the collection. /// - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { foreach (JProperty property in _properties) { - yield return new KeyValuePair(property.Name, property.Value); + yield return new KeyValuePair(property.Name, property.Value); } } @@ -735,16 +747,17 @@ PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() return ((ICustomTypeDescriptor)this).GetProperties(null); } - PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[]? attributes) { - PropertyDescriptorCollection descriptors = new PropertyDescriptorCollection(null); - - foreach (KeyValuePair propertyValue in this) + PropertyDescriptor[] propertiesArray = new PropertyDescriptor[Count]; + int i = 0; + foreach (KeyValuePair propertyValue in this) { - descriptors.Add(new JPropertyDescriptor(propertyValue.Key)); + propertiesArray[i] = new JPropertyDescriptor(propertyValue.Key); + i++; } - return descriptors; + return new PropertyDescriptorCollection(propertiesArray); } AttributeCollection ICustomTypeDescriptor.GetAttributes() @@ -752,12 +765,12 @@ AttributeCollection ICustomTypeDescriptor.GetAttributes() return AttributeCollection.Empty; } - string ICustomTypeDescriptor.GetClassName() + string? ICustomTypeDescriptor.GetClassName() { return null; } - string ICustomTypeDescriptor.GetComponentName() + string? ICustomTypeDescriptor.GetComponentName() { return null; } @@ -767,22 +780,22 @@ TypeConverter ICustomTypeDescriptor.GetConverter() return new TypeConverter(); } - EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() + EventDescriptor? ICustomTypeDescriptor.GetDefaultEvent() { return null; } - PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() + PropertyDescriptor? ICustomTypeDescriptor.GetDefaultProperty() { return null; } - object ICustomTypeDescriptor.GetEditor(Type editorBaseType) + object? ICustomTypeDescriptor.GetEditor(Type editorBaseType) { return null; } - EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) + EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[]? attributes) { return EventDescriptorCollection.Empty; } @@ -792,7 +805,7 @@ EventDescriptorCollection ICustomTypeDescriptor.GetEvents() return EventDescriptorCollection.Empty; } - object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) + object? ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor? pd) { if (pd is JPropertyDescriptor) { @@ -820,7 +833,7 @@ protected override DynamicMetaObject GetMetaObject(Expression parameter) private class JObjectDynamicProxy : DynamicProxy { - public override bool TryGetMember(JObject instance, GetMemberBinder binder, out object result) + public override bool TryGetMember(JObject instance, GetMemberBinder binder, out object? result) { // result can be null result = instance[binder.Name]; diff --git a/Src/Newtonsoft.Json/Linq/JProperty.Async.cs b/Src/Newtonsoft.Json/Linq/JProperty.Async.cs index 9083a9850..d1e845dce 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.Async.cs @@ -44,7 +44,7 @@ public partial class JProperty public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters) { Task task = writer.WritePropertyNameAsync(_name, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return WriteValueAsync(writer, cancellationToken, converters); } @@ -88,7 +88,7 @@ private Task WriteValueAsync(JsonWriter writer, CancellationToken cancellationTo /// The token to monitor for cancellation requests. The default value is . /// A representing the asynchronous creation. The /// property returns a that contains the JSON that was read from the specified . - public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public new static async Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { if (reader.TokenType == JsonToken.None) { @@ -105,7 +105,7 @@ private Task WriteValueAsync(JsonWriter writer, CancellationToken cancellationTo throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JProperty p = new JProperty((string)reader.Value); + JProperty p = new JProperty((string)reader.Value!); p.SetLineInfo(reader as IJsonLineInfo, settings); await p.ReadTokenFromAsync(reader, settings, cancellationToken).ConfigureAwait(false); diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index ab938a9b7..b8c7ace6a 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -40,7 +40,7 @@ public partial class JProperty : JContainer #region JPropertyList private class JPropertyList : IList { - internal JToken _token; + internal JToken? _token; public IEnumerator GetEnumerator() { @@ -115,13 +115,24 @@ public void RemoveAt(int index) public JToken this[int index] { - get => (index == 0) ? _token : null; + get + { + if (index != 0) + { + throw new IndexOutOfRangeException(); + } + + MiscellaneousUtils.Assert(_token != null); + return _token; + } set { - if (index == 0) + if (index != 0) { - _token = value; + throw new IndexOutOfRangeException(); } + + _token = value; } } } @@ -153,7 +164,7 @@ public string Name public JToken Value { [DebuggerStepThrough] - get { return _content._token; } + get { return _content._token!; } set { CheckReentrancy(); @@ -162,7 +173,7 @@ public JToken Value if (_content._token == null) { - InsertItem(0, newValue, false); + InsertItem(0, newValue, false, copyAnnotations: true); } else { @@ -176,7 +187,13 @@ public JToken Value /// /// A object to copy from. public JProperty(JProperty other) - : base(other) + : base(other, settings: null) + { + _name = other.Name; + } + + internal JProperty(JProperty other, JsonCloneSettings? settings) + : base(other, settings) { _name = other.Name; } @@ -191,7 +208,7 @@ internal override JToken GetItem(int index) return Value; } - internal override void SetItem(int index, JToken item) + internal override void SetItem(int index, JToken? item) { if (index != 0) { @@ -203,14 +220,14 @@ internal override void SetItem(int index, JToken item) return; } - ((JObject)Parent)?.InternalPropertyChanging(this); + ((JObject?)Parent)?.InternalPropertyChanging(this); base.SetItem(0, item); - ((JObject)Parent)?.InternalPropertyChanged(this); + ((JObject?)Parent)?.InternalPropertyChanged(this); } - internal override bool RemoveItem(JToken item) + internal override bool RemoveItem(JToken? item) { throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty))); } @@ -220,17 +237,22 @@ internal override void RemoveItemAt(int index) throw new JsonException("Cannot add or remove items from {0}.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty))); } - internal override int IndexOfItem(JToken item) + internal override int IndexOfItem(JToken? item) { + if (item == null) + { + return -1; + } + return _content.IndexOf(item); } - internal override void InsertItem(int index, JToken item, bool skipParentCheck) + internal override bool InsertItem(int index, JToken? item, bool skipParentCheck, bool copyAnnotations) { // don't add comments to JProperty if (item != null && item.Type == JTokenType.Comment) { - return; + return false; } if (Value != null) @@ -238,17 +260,17 @@ internal override void InsertItem(int index, JToken item, bool skipParentCheck) throw new JsonException("{0} cannot have multiple values.".FormatWith(CultureInfo.InvariantCulture, typeof(JProperty))); } - base.InsertItem(0, item, false); + return base.InsertItem(0, item, false, copyAnnotations); } - internal override bool ContainsItem(JToken item) + internal override bool ContainsItem(JToken? item) { return (Value == item); } - internal override void MergeItem(object content, JsonMergeSettings settings) + internal override void MergeItem(object content, JsonMergeSettings? settings) { - JToken value = (content as JProperty)?.Value; + JToken? value = (content as JProperty)?.Value; if (value != null && value.Type != JTokenType.Null) { @@ -266,9 +288,9 @@ internal override bool DeepEquals(JToken node) return (node is JProperty t && _name == t.Name && ContentsEqual(t)); } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings) { - return new JProperty(this); + return new JProperty(this, settings); } /// @@ -304,7 +326,7 @@ public JProperty(string name, params object[] content) /// /// The property name. /// The property content. - public JProperty(string name, object content) + public JProperty(string name, object? content) { ValidationUtils.ArgumentNotNull(name, nameof(name)); @@ -337,7 +359,13 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter internal override int GetDeepHashCode() { - return _name.GetHashCode() ^ (Value?.GetDeepHashCode() ?? 0); + int hash; +#if HAVE_GETHASHCODE_STRING_COMPARISON + hash = _name.GetHashCode(StringComparison.Ordinal); +#else + hash = _name.GetHashCode(); +#endif + return hash ^ (Value?.GetDeepHashCode() ?? 0); } /// @@ -357,7 +385,7 @@ internal override int GetDeepHashCode() /// The used to load the JSON. /// If this is null, default load settings will be used. /// A that contains the JSON that was read from the specified . - public new static JProperty Load(JsonReader reader, JsonLoadSettings settings) + public new static JProperty Load(JsonReader reader, JsonLoadSettings? settings) { if (reader.TokenType == JsonToken.None) { @@ -374,7 +402,7 @@ internal override int GetDeepHashCode() throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } - JProperty p = new JProperty((string)reader.Value); + JProperty p = new JProperty((string)reader.Value!); p.SetLineInfo(reader as IJsonLineInfo, settings); p.ReadTokenFrom(reader, settings); diff --git a/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs b/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs index 08858c038..606b2f2db 100644 --- a/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs +++ b/Src/Newtonsoft.Json/Linq/JPropertyDescriptor.cs @@ -67,7 +67,7 @@ public override bool CanResetValue(object component) /// The value of a property for a given component. /// /// The component with the property for which to retrieve the value. - public override object GetValue(object component) + public override object? GetValue(object? component) { return (component as JObject)?[Name]; } @@ -85,7 +85,7 @@ public override void ResetValue(object component) /// /// The component with the property value that is to be set. /// The new value. - public override void SetValue(object component, object value) + public override void SetValue(object? component, object? value) { if (component is JObject o) { diff --git a/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs b/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs index 435e45738..42a37d8af 100644 --- a/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs +++ b/Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs @@ -26,6 +26,8 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Newtonsoft.Json.Utilities; namespace Newtonsoft.Json.Linq @@ -34,7 +36,7 @@ internal class JPropertyKeyedCollection : Collection { private static readonly IEqualityComparer Comparer = StringComparer.Ordinal; - private Dictionary _dictionary; + private Dictionary? _dictionary; public JPropertyKeyedCollection() : base(new List()) { @@ -43,7 +45,7 @@ public JPropertyKeyedCollection() : base(new List()) private void AddKey(string key, JToken item) { EnsureDictionary(); - _dictionary[key] = item; + _dictionary![key] = item; } protected void ChangeItemKey(JToken item, string newKey) @@ -129,7 +131,7 @@ public bool Remove(string key) if (_dictionary != null) { - return _dictionary.TryGetValue(key, out JToken value) && Remove(value); + return _dictionary.TryGetValue(key, out JToken? value) && Remove(value); } return false; @@ -189,7 +191,7 @@ public JToken this[string key] } } - public bool TryGetValue(string key, out JToken value) + public bool TryGetValue(string key, [NotNullWhen(true)]out JToken? value) { if (_dictionary == null) { @@ -205,7 +207,7 @@ public ICollection Keys get { EnsureDictionary(); - return _dictionary.Keys; + return _dictionary!.Keys; } } @@ -214,7 +216,7 @@ public ICollection Values get { EnsureDictionary(); - return _dictionary.Values; + return _dictionary!.Values; } } @@ -232,8 +234,8 @@ public bool Compare(JPropertyKeyedCollection other) // dictionaries in JavaScript aren't ordered // ignore order when comparing properties - Dictionary d1 = _dictionary; - Dictionary d2 = other._dictionary; + Dictionary? d1 = _dictionary; + Dictionary? d2 = other._dictionary; if (d1 == null && d2 == null) { @@ -242,7 +244,7 @@ public bool Compare(JPropertyKeyedCollection other) if (d1 == null) { - return (d2.Count == 0); + return (d2!.Count == 0); } if (d2 == null) @@ -257,7 +259,7 @@ public bool Compare(JPropertyKeyedCollection other) foreach (KeyValuePair keyAndProperty in d1) { - if (!d2.TryGetValue(keyAndProperty.Key, out JToken secondValue)) + if (!d2.TryGetValue(keyAndProperty.Key, out JToken? secondValue)) { return false; } diff --git a/Src/Newtonsoft.Json/Linq/JRaw.cs b/Src/Newtonsoft.Json/Linq/JRaw.cs index 9acc240f0..02ca96d3c 100644 --- a/Src/Newtonsoft.Json/Linq/JRaw.cs +++ b/Src/Newtonsoft.Json/Linq/JRaw.cs @@ -38,7 +38,12 @@ public partial class JRaw : JValue /// /// A object to copy from. public JRaw(JRaw other) - : base(other) + : base(other, settings: null) + { + } + + internal JRaw(JRaw other, JsonCloneSettings? settings) + : base(other, settings) { } @@ -46,7 +51,7 @@ public JRaw(JRaw other) /// Initializes a new instance of the class. /// /// The raw json. - public JRaw(object rawJson) + public JRaw(object? rawJson) : base(rawJson, JTokenType.Raw) { } @@ -67,9 +72,9 @@ public static JRaw Create(JsonReader reader) } } - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings) { - return new JRaw(this); + return new JRaw(this, settings); } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JToken.Async.cs b/Src/Newtonsoft.Json/Linq/JToken.Async.cs index 1d89e0fdc..4d147c2d8 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.Async.cs @@ -89,7 +89,7 @@ public static Task ReadFromAsync(JsonReader reader, CancellationToken ca /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -101,7 +101,7 @@ public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettin } } - IJsonLineInfo lineInfo = reader as IJsonLineInfo; + IJsonLineInfo? lineInfo = reader as IJsonLineInfo; switch (reader.TokenType) { @@ -123,7 +123,7 @@ public static async Task ReadFromAsync(JsonReader reader, JsonLoadSettin v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Comment: - v = JValue.CreateComment(reader.Value.ToString()); + v = JValue.CreateComment(reader.Value?.ToString()); v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Null: @@ -168,7 +168,7 @@ public static Task LoadAsync(JsonReader reader, CancellationToken cancel /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static Task LoadAsync(JsonReader reader, JsonLoadSettings settings, CancellationToken cancellationToken = default) + public static Task LoadAsync(JsonReader reader, JsonLoadSettings? settings, CancellationToken cancellationToken = default) { return ReadFromAsync(reader, settings, cancellationToken); } diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 05f641c1d..27f84d8ba 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -38,12 +38,14 @@ using System.Diagnostics; using System.Globalization; using System.Collections; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; - #endif +using Newtonsoft.Json.Serialization; namespace Newtonsoft.Json.Linq { @@ -58,12 +60,12 @@ public abstract partial class JToken : IJEnumerable, IJsonLineInfo , IDynamicMetaObjectProvider #endif { - private static JTokenEqualityComparer _equalityComparer; + private static JTokenEqualityComparer? _equalityComparer; - private JContainer _parent; - private JToken _previous; - private JToken _next; - private object _annotations; + private JContainer? _parent; + private JToken? _previous; + private JToken? _next; + private object? _annotations; private static readonly JTokenType[] BooleanTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean }; private static readonly JTokenType[] NumberTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean }; @@ -99,7 +101,7 @@ public static JTokenEqualityComparer EqualityComparer /// Gets or sets the parent. /// /// The parent. - public JContainer Parent + public JContainer? Parent { [DebuggerStepThrough] get { return _parent; } @@ -114,7 +116,7 @@ public JToken Root { get { - JContainer parent = Parent; + JContainer? parent = Parent; if (parent == null) { return this; @@ -129,7 +131,7 @@ public JToken Root } } - internal abstract JToken CloneToken(); + internal abstract JToken CloneToken(JsonCloneSettings? settings); internal abstract bool DeepEquals(JToken node); /// @@ -152,7 +154,7 @@ public JToken Root /// The first to compare. /// The second to compare. /// true if the tokens are equal; otherwise false. - public static bool DeepEquals(JToken t1, JToken t2) + public static bool DeepEquals(JToken? t1, JToken? t2) { return (t1 == t2 || (t1 != null && t2 != null && t1.DeepEquals(t2))); } @@ -161,7 +163,7 @@ public static bool DeepEquals(JToken t1, JToken t2) /// Gets the next sibling token of this node. /// /// The that contains the next sibling token. - public JToken Next + public JToken? Next { get => _next; internal set => _next = value; @@ -171,7 +173,7 @@ public JToken Next /// Gets the previous sibling token of this node. /// /// The that contains the previous sibling token. - public JToken Previous + public JToken? Previous { get => _previous; internal set => _previous = value; @@ -190,8 +192,8 @@ public string Path } List positions = new List(); - JToken previous = null; - for (JToken current = this; current != null; current = current.Parent) + JToken? previous = null; + for (JToken? current = this; current != null; current = current.Parent) { switch (current.Type) { @@ -231,7 +233,7 @@ internal JToken() /// Adds the specified content immediately after this token. /// /// A content object that contains simple content or a collection of content objects to be added after this token. - public void AddAfterSelf(object content) + public void AddAfterSelf(object? content) { if (_parent == null) { @@ -239,14 +241,14 @@ public void AddAfterSelf(object content) } int index = _parent.IndexOfItem(this); - _parent.AddInternal(index + 1, content, false); + _parent.TryAddInternal(index + 1, content, false, copyAnnotations: true); } /// /// Adds the specified content immediately before this token. /// /// A content object that contains simple content or a collection of content objects to be added before this token. - public void AddBeforeSelf(object content) + public void AddBeforeSelf(object? content) { if (_parent == null) { @@ -254,7 +256,7 @@ public void AddBeforeSelf(object content) } int index = _parent.IndexOfItem(this); - _parent.AddInternal(index, content, false); + _parent.TryAddInternal(index, content, false, copyAnnotations: true); } /// @@ -277,7 +279,7 @@ public IEnumerable AncestorsAndSelf() internal IEnumerable GetAncestors(bool self) { - for (JToken current = self ? this : Parent; current != null; current = current.Parent) + for (JToken? current = self ? this : Parent; current != null; current = current.Parent) { yield return current; } @@ -294,7 +296,7 @@ public IEnumerable AfterSelf() yield break; } - for (JToken o = Next; o != null; o = o.Next) + for (JToken? o = Next; o != null; o = o.Next) { yield return o; } @@ -306,7 +308,12 @@ public IEnumerable AfterSelf() /// A collection of the sibling tokens before this token, in document order. public IEnumerable BeforeSelf() { - for (JToken o = Parent.First; o != this; o = o.Next) + if (Parent == null) + { + yield break; + } + + for (JToken? o = Parent.First; o != this && o != null; o = o.Next) { yield return o; } @@ -316,7 +323,7 @@ public IEnumerable BeforeSelf() /// Gets the with the specified key. /// /// The with the specified key. - public virtual JToken this[object key] + public virtual JToken? this[object key] { get => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); set => throw new InvalidOperationException("Cannot set child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); @@ -328,9 +335,9 @@ public virtual JToken this[object key] /// The type to convert the token to. /// The token key. /// The converted token value. - public virtual T Value(object key) + public virtual T? Value(object key) { - JToken token = this[key]; + JToken? token = this[key]; // null check to fix MonoTouch issue - https://github.com/dolbz/Newtonsoft.Json/commit/a24e3062846b30ee505f3271ac08862bb471b822 return token == null ? default : Extensions.Convert(token); @@ -340,13 +347,13 @@ public virtual T Value(object key) /// Get the first child token of this token. /// /// A containing the first child token of the . - public virtual JToken First => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); + public virtual JToken? First => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); /// /// Get the last child token of this token. /// /// A containing the last child token of the . - public virtual JToken Last => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); + public virtual JToken? Last => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); /// /// Returns a collection of the child tokens of this token, in document order. @@ -372,7 +379,7 @@ public JEnumerable Children() where T : JToken /// /// The type to convert the values to. /// A containing the child values of this , in document order. - public virtual IEnumerable Values() + public virtual IEnumerable Values() { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } @@ -414,6 +421,10 @@ public void Replace(JToken value) /// /// Returns the indented JSON for this token. /// + /// + /// ToString() returns a non-JSON string value for tokens with a type of . + /// If you want the JSON for all token types then you should use . + /// /// /// The indented JSON for this token. /// @@ -441,7 +452,7 @@ public string ToString(Formatting formatting, params JsonConverter[] converters) } } - private static JValue EnsureValue(JToken value) + private static JValue? EnsureValue(JToken value) { if (value == null) { @@ -453,7 +464,7 @@ private static JValue EnsureValue(JToken value) value = property.Value; } - JValue v = value as JValue; + JValue? v = value as JValue; return v; } @@ -475,7 +486,7 @@ private static bool ValidateToken(JToken o, JTokenType[] validTypes, bool nullab return (Array.IndexOf(validTypes, o.Type) != -1) || (nullable && (o.Type == JTokenType.Null || o.Type == JTokenType.Undefined)); } -#region Cast from operators + #region Cast from operators /// /// Performs an explicit conversion from to . /// @@ -483,7 +494,7 @@ private static bool ValidateToken(JToken o, JTokenType[] validTypes, bool nullab /// The result of the conversion. public static explicit operator bool(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BooleanTypes, false)) { throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -507,7 +518,7 @@ public static explicit operator bool(JToken value) /// The result of the conversion. public static explicit operator DateTimeOffset(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, false)) { throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -532,14 +543,14 @@ public static explicit operator DateTimeOffset(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator bool?(JToken value) + public static explicit operator bool?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BooleanTypes, true)) { throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -562,7 +573,7 @@ public static explicit operator DateTimeOffset(JToken value) /// The result of the conversion. public static explicit operator long(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -583,14 +594,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator DateTime?(JToken value) + public static explicit operator DateTime?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, true)) { throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -612,14 +623,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator DateTimeOffset?(JToken value) + public static explicit operator DateTimeOffset?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, true)) { throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -648,14 +659,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator decimal?(JToken value) + public static explicit operator decimal?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -676,14 +687,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator double?(JToken value) + public static explicit operator double?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -704,14 +715,14 @@ public static explicit operator long(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator char?(JToken value) + public static explicit operator char?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, CharTypes, true)) { throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -734,7 +745,7 @@ public static explicit operator long(JToken value) /// The result of the conversion. public static explicit operator int(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -757,7 +768,7 @@ public static explicit operator int(JToken value) /// The result of the conversion. public static explicit operator short(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Int16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -781,7 +792,7 @@ public static explicit operator short(JToken value) [CLSCompliant(false)] public static explicit operator ushort(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to UInt16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -805,7 +816,7 @@ public static explicit operator ushort(JToken value) [CLSCompliant(false)] public static explicit operator char(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, CharTypes, false)) { throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -828,7 +839,7 @@ public static explicit operator char(JToken value) /// The result of the conversion. public static explicit operator byte(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -852,7 +863,7 @@ public static explicit operator byte(JToken value) [CLSCompliant(false)] public static explicit operator sbyte(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to SByte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -873,14 +884,14 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator int?(JToken value) + public static explicit operator int?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -901,14 +912,14 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator short?(JToken value) + public static explicit operator short?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Int16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -930,14 +941,14 @@ public static explicit operator sbyte(JToken value) /// The value. /// The result of the conversion. [CLSCompliant(false)] - public static explicit operator ushort?(JToken value) + public static explicit operator ushort?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to UInt16.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -958,14 +969,14 @@ public static explicit operator sbyte(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator byte?(JToken value) + public static explicit operator byte?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -987,14 +998,14 @@ public static explicit operator sbyte(JToken value) /// The value. /// The result of the conversion. [CLSCompliant(false)] - public static explicit operator sbyte?(JToken value) + public static explicit operator sbyte?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to SByte.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1017,7 +1028,7 @@ public static explicit operator sbyte(JToken value) /// The result of the conversion. public static explicit operator DateTime(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, DateTimeTypes, false)) { throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1038,14 +1049,14 @@ public static explicit operator DateTime(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator long?(JToken value) + public static explicit operator long?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1066,14 +1077,14 @@ public static explicit operator DateTime(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator float?(JToken value) + public static explicit operator float?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1096,7 +1107,7 @@ public static explicit operator DateTime(JToken value) /// The result of the conversion. public static explicit operator decimal(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1118,14 +1129,14 @@ public static explicit operator decimal(JToken value) /// The value. /// The result of the conversion. [CLSCompliant(false)] - public static explicit operator uint?(JToken value) + public static explicit operator uint?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1147,14 +1158,14 @@ public static explicit operator decimal(JToken value) /// The value. /// The result of the conversion. [CLSCompliant(false)] - public static explicit operator ulong?(JToken value) + public static explicit operator ulong?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, true)) { throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1177,7 +1188,7 @@ public static explicit operator decimal(JToken value) /// The result of the conversion. public static explicit operator double(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1200,7 +1211,7 @@ public static explicit operator double(JToken value) /// The result of the conversion. public static explicit operator float(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1221,14 +1232,14 @@ public static explicit operator float(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator string(JToken value) + public static explicit operator string?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, StringTypes, true)) { throw new ArgumentException("Can not convert {0} to String.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1262,7 +1273,7 @@ public static explicit operator string(JToken value) [CLSCompliant(false)] public static explicit operator uint(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1286,7 +1297,7 @@ public static explicit operator uint(JToken value) [CLSCompliant(false)] public static explicit operator ulong(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, NumberTypes, false)) { throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1307,14 +1318,14 @@ public static explicit operator ulong(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator byte[](JToken value) + public static explicit operator byte[]?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BytesTypes, false)) { throw new ArgumentException("Can not convert {0} to byte array.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1322,7 +1333,7 @@ public static explicit operator byte[](JToken value) if (v.Value is string) { - return Convert.FromBase64String(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return Convert.FromBase64String(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } #if HAVE_BIG_INTEGER if (v.Value is BigInteger integer) @@ -1346,7 +1357,7 @@ public static explicit operator byte[](JToken value) /// The result of the conversion. public static explicit operator Guid(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, GuidTypes, false)) { throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1357,7 +1368,7 @@ public static explicit operator Guid(JToken value) return new Guid(bytes); } - return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1365,14 +1376,14 @@ public static explicit operator Guid(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator Guid?(JToken value) + public static explicit operator Guid?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, GuidTypes, true)) { throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1388,7 +1399,7 @@ public static explicit operator Guid(JToken value) return new Guid(bytes); } - return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1398,13 +1409,13 @@ public static explicit operator Guid(JToken value) /// The result of the conversion. public static explicit operator TimeSpan(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, TimeSpanTypes, false)) { throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); } - return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1412,14 +1423,14 @@ public static explicit operator TimeSpan(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator TimeSpan?(JToken value) + public static explicit operator TimeSpan?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, TimeSpanTypes, true)) { throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1430,7 +1441,7 @@ public static explicit operator TimeSpan(JToken value) return null; } - return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } /// @@ -1438,14 +1449,14 @@ public static explicit operator TimeSpan(JToken value) /// /// The value. /// The result of the conversion. - public static explicit operator Uri(JToken value) + public static explicit operator Uri?(JToken? value) { if (value == null) { return null; } - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, UriTypes, true)) { throw new ArgumentException("Can not convert {0} to Uri.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1456,24 +1467,24 @@ public static explicit operator Uri(JToken value) return null; } - return (v.Value is Uri uri) ? uri : new Uri(Convert.ToString(v.Value, CultureInfo.InvariantCulture)); + return (v.Value is Uri uri) ? uri : new Uri(Convert.ToString(v.Value, CultureInfo.InvariantCulture)!); } #if HAVE_BIG_INTEGER private static BigInteger ToBigInteger(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BigIntegerTypes, false)) { throw new ArgumentException("Can not convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); } - return ConvertUtils.ToBigInteger(v.Value); + return ConvertUtils.ToBigInteger(v.Value!); } private static BigInteger? ToBigIntegerNullable(JToken value) { - JValue v = EnsureValue(value); + JValue? v = EnsureValue(value); if (v == null || !ValidateToken(v, BigIntegerTypes, true)) { throw new ArgumentException("Can not convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); @@ -1487,9 +1498,9 @@ private static BigInteger ToBigInteger(JToken value) return ConvertUtils.ToBigInteger(v.Value); } #endif -#endregion + #endregion -#region Cast to operators + #region Cast to operators /// /// Performs an implicit conversion from to . /// @@ -1767,7 +1778,7 @@ public static implicit operator JToken(float value) /// /// The value to create a from. /// The initialized with the specified value. - public static implicit operator JToken(string value) + public static implicit operator JToken(string? value) { return new JValue(value); } @@ -1809,7 +1820,7 @@ public static implicit operator JToken(byte[] value) /// /// The value to create a from. /// The initialized with the specified value. - public static implicit operator JToken(Uri value) + public static implicit operator JToken(Uri? value) { return new JValue(value); } @@ -1853,7 +1864,7 @@ public static implicit operator JToken(Guid? value) { return new JValue(value); } -#endregion + #endregion IEnumerator IEnumerable.GetEnumerator() { @@ -1867,7 +1878,7 @@ IEnumerator IEnumerable.GetEnumerator() internal abstract int GetDeepHashCode(); - IJEnumerable IJEnumerable.this[object key] => this[key]; + IJEnumerable IJEnumerable.this[object key] => this[key]!; /// /// Creates a for this token. @@ -1887,7 +1898,7 @@ internal static JToken FromObjectInternal(object o, JsonSerializer jsonSerialize using (JTokenWriter jsonWriter = new JTokenWriter()) { jsonSerializer.Serialize(jsonWriter, o); - token = jsonWriter.Token; + token = jsonWriter.Token!; } return token; @@ -1919,9 +1930,9 @@ public static JToken FromObject(object o, JsonSerializer jsonSerializer) /// /// The object type that the token will be deserialized to. /// The new object created from the JSON value. - public T ToObject() + public T? ToObject() { - return (T)ToObject(typeof(T)); + return (T?)ToObject(typeof(T)); } /// @@ -1929,7 +1940,7 @@ public T ToObject() /// /// The object type that the token will be deserialized to. /// The new object created from the JSON value. - public object ToObject(Type objectType) + public object? ToObject(Type objectType) { if (JsonConvert.DefaultSettings == null) { @@ -1946,15 +1957,15 @@ public object ToObject(Type objectType) } catch (Exception ex) { - Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType); - throw new ArgumentException("Could not convert '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, (string)this, enumType.Name), ex); + Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType)!; + throw new ArgumentException("Could not convert '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, (string?)this, enumType.Name), ex); } } if (Type == JTokenType.Integer) { - Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType); - return Enum.ToObject(enumType, ((JValue)this).Value); + Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType)!; + return Enum.ToObject(enumType, ((JValue)this).Value!); } } @@ -2023,13 +2034,13 @@ public object ToObject(Type objectType) return (DateTimeOffset)this; #endif case PrimitiveTypeCode.String: - return (string)this; + return (string?)this; case PrimitiveTypeCode.GuidNullable: return (Guid?)this; case PrimitiveTypeCode.Guid: return (Guid)this; case PrimitiveTypeCode.Uri: - return (Uri)this; + return (Uri?)this; case PrimitiveTypeCode.TimeSpanNullable: return (TimeSpan?)this; case PrimitiveTypeCode.TimeSpan: @@ -2052,9 +2063,9 @@ public object ToObject(Type objectType) /// The object type that the token will be deserialized to. /// The that will be used when creating the object. /// The new object created from the JSON value. - public T ToObject(JsonSerializer jsonSerializer) + public T? ToObject(JsonSerializer jsonSerializer) { - return (T)ToObject(typeof(T), jsonSerializer); + return (T?)ToObject(typeof(T), jsonSerializer); } /// @@ -2063,12 +2074,19 @@ public T ToObject(JsonSerializer jsonSerializer) /// The object type that the token will be deserialized to. /// The that will be used when creating the object. /// The new object created from the JSON value. - public object ToObject(Type objectType, JsonSerializer jsonSerializer) + public object? ToObject(Type? objectType, JsonSerializer jsonSerializer) { ValidationUtils.ArgumentNotNull(jsonSerializer, nameof(jsonSerializer)); using (JTokenReader jsonReader = new JTokenReader(this)) { + // Hacky fix to ensure the serializer settings are set onto the new reader. + // This is required because the serializer won't update settings when used inside of a converter. + if (jsonSerializer is JsonSerializerProxy proxy) + { + proxy._serializer.SetupReader(jsonReader, out _, out _, out _, out _, out _, out _); + } + return jsonSerializer.Deserialize(jsonReader, objectType); } } @@ -2098,7 +2116,7 @@ public static JToken ReadFrom(JsonReader reader) /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static JToken ReadFrom(JsonReader reader, JsonLoadSettings settings) + public static JToken ReadFrom(JsonReader reader, JsonLoadSettings? settings) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -2123,7 +2141,7 @@ public static JToken ReadFrom(JsonReader reader, JsonLoadSettings settings) throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader."); } - IJsonLineInfo lineInfo = reader as IJsonLineInfo; + IJsonLineInfo? lineInfo = reader as IJsonLineInfo; switch (reader.TokenType) { @@ -2145,7 +2163,7 @@ public static JToken ReadFrom(JsonReader reader, JsonLoadSettings settings) v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Comment: - v = JValue.CreateComment(reader.Value.ToString()); + v = JValue.CreateComment(reader.Value!.ToString()); v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Null: @@ -2178,7 +2196,7 @@ public static JToken Parse(string json) /// The used to load the JSON. /// If this is null, default load settings will be used. /// A populated from the string that contains JSON. - public static JToken Parse(string json, JsonLoadSettings settings) + public static JToken Parse(string json, JsonLoadSettings? settings) { using (JsonReader reader = new JsonTextReader(new StringReader(json))) { @@ -2189,7 +2207,6 @@ public static JToken Parse(string json, JsonLoadSettings settings) // Any content encountered here other than a comment will throw in the reader. } - return t; } } @@ -2205,7 +2222,7 @@ public static JToken Parse(string json, JsonLoadSettings settings) /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// - public static JToken Load(JsonReader reader, JsonLoadSettings settings) + public static JToken Load(JsonReader reader, JsonLoadSettings? settings) { return ReadFrom(reader, settings); } @@ -2224,7 +2241,7 @@ public static JToken Load(JsonReader reader) return Load(reader, null); } - internal void SetLineInfo(IJsonLineInfo lineInfo, JsonLoadSettings settings) + internal void SetLineInfo(IJsonLineInfo? lineInfo, JsonLoadSettings? settings) { if (settings != null && settings.LineInfoHandling != LineInfoHandling.Load) { @@ -2265,7 +2282,7 @@ int IJsonLineInfo.LineNumber { get { - LineInfoAnnotation annotation = Annotation(); + LineInfoAnnotation? annotation = Annotation(); if (annotation != null) { return annotation.LineNumber; @@ -2279,7 +2296,7 @@ int IJsonLineInfo.LinePosition { get { - LineInfoAnnotation annotation = Annotation(); + LineInfoAnnotation? annotation = Annotation(); if (annotation != null) { return annotation.LinePosition; @@ -2290,31 +2307,48 @@ int IJsonLineInfo.LinePosition } /// - /// Selects a using a JPath expression. Selects the token that matches the object path. + /// Selects a using a JSONPath expression. Selects the token that matches the object path. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// A , or null. - public JToken SelectToken(string path) + public JToken? SelectToken(string path) { - return SelectToken(path, false); + return SelectToken(path, settings: null); } /// - /// Selects a using a JPath expression. Selects the token that matches the object path. + /// Selects a using a JSONPath expression. Selects the token that matches the object path. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression. /// A . - public JToken SelectToken(string path, bool errorWhenNoMatch) + public JToken? SelectToken(string path, bool errorWhenNoMatch) + { + JsonSelectSettings? settings = errorWhenNoMatch + ? new JsonSelectSettings { ErrorWhenNoMatch = true } + : null; + + return SelectToken(path, settings); + } + + /// + /// Selects a using a JSONPath expression. Selects the token that matches the object path. + /// + /// + /// A that contains a JSONPath expression. + /// + /// The used to select tokens. + /// A . + public JToken? SelectToken(string path, JsonSelectSettings? settings) { JPath p = new JPath(path); - JToken token = null; - foreach (JToken t in p.Evaluate(this, this, errorWhenNoMatch)) + JToken? token = null; + foreach (JToken t in p.Evaluate(this, this, settings)) { if (token != null) { @@ -2328,29 +2362,46 @@ public JToken SelectToken(string path, bool errorWhenNoMatch) } /// - /// Selects a collection of elements using a JPath expression. + /// Selects a collection of elements using a JSONPath expression. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// An of that contains the selected elements. public IEnumerable SelectTokens(string path) { - return SelectTokens(path, false); + return SelectTokens(path, settings: null); } /// - /// Selects a collection of elements using a JPath expression. + /// Selects a collection of elements using a JSONPath expression. /// /// - /// A that contains a JPath expression. + /// A that contains a JSONPath expression. /// /// A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression. /// An of that contains the selected elements. public IEnumerable SelectTokens(string path, bool errorWhenNoMatch) { - JPath p = new JPath(path); - return p.Evaluate(this, this, errorWhenNoMatch); + JsonSelectSettings? settings = errorWhenNoMatch + ? new JsonSelectSettings { ErrorWhenNoMatch = true } + : null; + + return SelectTokens(path, settings); + } + + /// + /// Selects a collection of elements using a JSONPath expression. + /// + /// + /// A that contains a JSONPath expression. + /// + /// The used to select tokens. + /// An of that contains the selected elements. + public IEnumerable SelectTokens(string path, JsonSelectSettings? settings) + { + var p = new JPath(path); + return p.Evaluate(this, this, settings); } #if HAVE_DYNAMIC @@ -2392,7 +2443,17 @@ object ICloneable.Clone() /// A new instance of the . public JToken DeepClone() { - return CloneToken(); + return CloneToken(settings: null); + } + + /// + /// Creates a new instance of the . All child tokens are recursively cloned. + /// + /// A object to configure cloning settings. + /// A new instance of the . + public JToken DeepClone(JsonCloneSettings settings) + { + return CloneToken(settings); } /// @@ -2438,7 +2499,7 @@ public void AddAnnotation(object annotation) /// /// The type of the annotation to retrieve. /// The first annotation object that matches the specified type, or null if no annotation is of the specified type. - public T Annotation() where T : class + public T? Annotation() where T : class { if (_annotations != null) { @@ -2469,7 +2530,7 @@ public T Annotation() where T : class /// /// The of the annotation to retrieve. /// The first annotation object that matches the specified type, or null if no annotation is of the specified type. - public object Annotation(Type type) + public object? Annotation(Type type) { if (type == null) { @@ -2595,7 +2656,7 @@ public void RemoveAnnotations() where T : class { if (_annotations != null) { - if (!(_annotations is object[] annotations)) + if (!(_annotations is object?[] annotations)) { if (_annotations is T) { @@ -2608,7 +2669,7 @@ public void RemoveAnnotations() where T : class int keepCount = 0; while (index < annotations.Length) { - object obj2 = annotations[index]; + object? obj2 = annotations[index]; if (obj2 == null) { break; @@ -2650,7 +2711,7 @@ public void RemoveAnnotations(Type type) if (_annotations != null) { - if (!(_annotations is object[] annotations)) + if (!(_annotations is object?[] annotations)) { if (type.IsInstanceOfType(_annotations)) { @@ -2663,7 +2724,7 @@ public void RemoveAnnotations(Type type) int keepCount = 0; while (index < annotations.Length) { - object o = annotations[index]; + object? o = annotations[index]; if (o == null) { break; @@ -2691,5 +2752,17 @@ public void RemoveAnnotations(Type type) } } } + + internal void CopyAnnotations(JToken target, JToken source) + { + if (source._annotations is object[] annotations) + { + target._annotations = annotations.ToArray(); + } + else + { + target._annotations = source._annotations; + } + } } -} \ No newline at end of file +} diff --git a/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs b/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs index 2930896d9..8e5314b21 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenEqualityComparer.cs @@ -40,7 +40,7 @@ public class JTokenEqualityComparer : IEqualityComparer /// /// true if the specified objects are equal; otherwise, false. /// - public bool Equals(JToken x, JToken y) + public bool Equals(JToken? x, JToken? y) { return JToken.DeepEquals(x, y); } diff --git a/Src/Newtonsoft.Json/Linq/JTokenReader.cs b/Src/Newtonsoft.Json/Linq/JTokenReader.cs index 7a97705cb..03d21c8a4 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenReader.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenReader.cs @@ -34,14 +34,14 @@ namespace Newtonsoft.Json.Linq public class JTokenReader : JsonReader, IJsonLineInfo { private readonly JToken _root; - private string _initialPath; - private JToken _parent; - private JToken _current; + private string? _initialPath; + private JToken? _parent; + private JToken? _current; /// /// Gets the at the reader's current position. /// - public JToken CurrentToken => _current; + public JToken? CurrentToken => _current; /// /// Initializes a new instance of the class. @@ -90,6 +90,12 @@ public override bool Read() } } + // The current value could already be the root value if it is a comment + if (_current == _root) + { + return false; + } + _current = _root; SetToken(_current); return true; @@ -102,8 +108,8 @@ private bool ReadOver(JToken t) return ReadToEnd(); } - JToken next = t.Next; - if ((next == null || next == t) || t == t.Parent.Last) + JToken? next = t.Next; + if ((next == null || next == t) || t == t.Parent!.Last) { if (t.Parent == null) { @@ -146,7 +152,7 @@ private bool ReadToEnd() private bool ReadInto(JContainer c) { - JToken firstChild = c.First; + JToken? firstChild = c.First; if (firstChild == null) { return SetEnd(c); @@ -215,7 +221,7 @@ private void SetToken(JToken token) break; case JTokenType.Date: { - object v = ((JValue)token).Value; + object? v = ((JValue)token).Value; if (v is DateTime dt) { v = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); @@ -235,7 +241,7 @@ private void SetToken(JToken token) break; case JTokenType.Uri: { - object v = ((JValue)token).Value; + object? v = ((JValue)token).Value; SetToken(JsonToken.String, v is Uri uri ? uri.OriginalString : SafeToString(v)); break; } @@ -247,7 +253,7 @@ private void SetToken(JToken token) } } - private string SafeToString(object value) + private string? SafeToString(object? value) { return value?.ToString(); } @@ -259,7 +265,7 @@ bool IJsonLineInfo.HasLineInfo() return false; } - IJsonLineInfo info = _current; + IJsonLineInfo? info = _current; return (info != null && info.HasLineInfo()); } @@ -272,7 +278,7 @@ int IJsonLineInfo.LineNumber return 0; } - IJsonLineInfo info = _current; + IJsonLineInfo? info = _current; if (info != null) { return info.LineNumber; @@ -291,7 +297,7 @@ int IJsonLineInfo.LinePosition return 0; } - IJsonLineInfo info = _current; + IJsonLineInfo? info = _current; if (info != null) { return info.LinePosition; @@ -315,9 +321,9 @@ public override string Path _initialPath = _root.Path; } - if (!string.IsNullOrEmpty(_initialPath)) + if (!StringUtils.IsNullOrEmpty(_initialPath)) { - if (string.IsNullOrEmpty(path)) + if (StringUtils.IsNullOrEmpty(path)) { return _initialPath; } diff --git a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs index 3c8230175..618063e24 100644 --- a/Src/Newtonsoft.Json/Linq/JTokenWriter.cs +++ b/Src/Newtonsoft.Json/Linq/JTokenWriter.cs @@ -24,6 +24,7 @@ #endregion using System; +using System.Diagnostics; using System.Globalization; #if HAVE_BIG_INTEGER using System.Numerics; @@ -37,22 +38,22 @@ namespace Newtonsoft.Json.Linq /// public partial class JTokenWriter : JsonWriter { - private JContainer _token; - private JContainer _parent; + private JContainer? _token; + private JContainer? _parent; // used when writer is writing single value and the value has no containing parent - private JValue _value; - private JToken _current; + private JValue? _value; + private JToken? _current; /// /// Gets the at the writer's current position. /// - public JToken CurrentToken => _current; + public JToken? CurrentToken => _current; /// /// Gets the token being written. /// /// The token being written. - public JToken Token + public JToken? Token { get { @@ -131,7 +132,7 @@ private void AddParent(JContainer container) private void RemoveParent() { _current = _parent; - _parent = _parent.Parent; + _parent = _parent!.Parent; if (_parent != null && _parent.Type == JTokenType.Property) { @@ -186,21 +187,26 @@ public override void WritePropertyName(string name) base.WritePropertyName(name); } - private void AddValue(object value, JsonToken token) + private void AddRawValue(object? value, JTokenType type, JsonToken token) { - AddValue(new JValue(value), token); + AddJValue(new JValue(value, type), token); } - internal void AddValue(JValue value, JsonToken token) + internal void AddJValue(JValue? value, JsonToken token) { if (_parent != null) { - _parent.Add(value); - _current = _parent.Last; - - if (_parent.Type == JTokenType.Property) + // TryAdd will return false if an invalid JToken type is added. + // For example, a JComment can't be added to a JObject. + // If there is an invalid JToken type then skip it. + if (_parent.TryAdd(value)) { - _parent = _parent.Parent; + _current = _parent.Last; + + if (_parent.Type == JTokenType.Property) + { + _parent = _parent.Parent; + } } } else @@ -216,13 +222,13 @@ internal void AddValue(JValue value, JsonToken token) /// An error will be raised if the value cannot be written as a single JSON token. /// /// The value to write. - public override void WriteValue(object value) + public override void WriteValue(object? value) { #if HAVE_BIG_INTEGER if (value is BigInteger) { InternalWriteValue(JsonToken.Integer); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } else #endif @@ -237,7 +243,7 @@ public override void WriteValue(object value) public override void WriteNull() { base.WriteNull(); - AddValue(null, JsonToken.Null); + AddJValue(JValue.CreateNull(), JsonToken.Null); } /// @@ -246,37 +252,37 @@ public override void WriteNull() public override void WriteUndefined() { base.WriteUndefined(); - AddValue(null, JsonToken.Undefined); + AddJValue(JValue.CreateUndefined(), JsonToken.Undefined); } /// /// Writes raw JSON. /// /// The raw JSON to write. - public override void WriteRaw(string json) + public override void WriteRaw(string? json) { base.WriteRaw(json); - AddValue(new JRaw(json), JsonToken.Raw); + AddJValue(new JRaw(json), JsonToken.Raw); } /// /// Writes a comment /*...*/ containing the specified text. /// /// Text to place inside the comment. - public override void WriteComment(string text) + public override void WriteComment(string? text) { base.WriteComment(text); - AddValue(JValue.CreateComment(text), JsonToken.Comment); + AddJValue(JValue.CreateComment(text), JsonToken.Comment); } /// /// Writes a value. /// /// The value to write. - public override void WriteValue(string value) + public override void WriteValue(string? value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } /// @@ -286,7 +292,7 @@ public override void WriteValue(string value) public override void WriteValue(int value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -297,7 +303,7 @@ public override void WriteValue(int value) public override void WriteValue(uint value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -307,7 +313,7 @@ public override void WriteValue(uint value) public override void WriteValue(long value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddJValue(new JValue(value), JsonToken.Integer); } /// @@ -318,7 +324,7 @@ public override void WriteValue(long value) public override void WriteValue(ulong value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddJValue(new JValue(value), JsonToken.Integer); } /// @@ -328,7 +334,7 @@ public override void WriteValue(ulong value) public override void WriteValue(float value) { base.WriteValue(value); - AddValue(value, JsonToken.Float); + AddJValue(new JValue(value), JsonToken.Float); } /// @@ -338,7 +344,7 @@ public override void WriteValue(float value) public override void WriteValue(double value) { base.WriteValue(value); - AddValue(value, JsonToken.Float); + AddJValue(new JValue(value), JsonToken.Float); } /// @@ -348,7 +354,7 @@ public override void WriteValue(double value) public override void WriteValue(bool value) { base.WriteValue(value); - AddValue(value, JsonToken.Boolean); + AddJValue(new JValue(value), JsonToken.Boolean); } /// @@ -358,7 +364,7 @@ public override void WriteValue(bool value) public override void WriteValue(short value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -369,7 +375,7 @@ public override void WriteValue(short value) public override void WriteValue(ushort value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -385,7 +391,7 @@ public override void WriteValue(char value) #else s = value.ToString(); #endif - AddValue(s, JsonToken.String); + AddJValue(new JValue(s), JsonToken.String); } /// @@ -395,7 +401,7 @@ public override void WriteValue(char value) public override void WriteValue(byte value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -406,7 +412,7 @@ public override void WriteValue(byte value) public override void WriteValue(sbyte value) { base.WriteValue(value); - AddValue(value, JsonToken.Integer); + AddRawValue(value, JTokenType.Integer, JsonToken.Integer); } /// @@ -416,7 +422,7 @@ public override void WriteValue(sbyte value) public override void WriteValue(decimal value) { base.WriteValue(value); - AddValue(value, JsonToken.Float); + AddJValue(new JValue(value), JsonToken.Float); } /// @@ -427,7 +433,7 @@ public override void WriteValue(DateTime value) { base.WriteValue(value); value = DateTimeUtils.EnsureDateTime(value, DateTimeZoneHandling); - AddValue(value, JsonToken.Date); + AddJValue(new JValue(value), JsonToken.Date); } #if HAVE_DATE_TIME_OFFSET @@ -438,7 +444,7 @@ public override void WriteValue(DateTime value) public override void WriteValue(DateTimeOffset value) { base.WriteValue(value); - AddValue(value, JsonToken.Date); + AddJValue(new JValue(value), JsonToken.Date); } #endif @@ -446,10 +452,10 @@ public override void WriteValue(DateTimeOffset value) /// Writes a [] value. /// /// The [] value to write. - public override void WriteValue(byte[] value) + public override void WriteValue(byte[]? value) { base.WriteValue(value); - AddValue(value, JsonToken.Bytes); + AddJValue(new JValue(value, JTokenType.Bytes), JsonToken.Bytes); } /// @@ -459,7 +465,7 @@ public override void WriteValue(byte[] value) public override void WriteValue(TimeSpan value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } /// @@ -469,17 +475,17 @@ public override void WriteValue(TimeSpan value) public override void WriteValue(Guid value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } /// /// Writes a value. /// /// The value to write. - public override void WriteValue(Uri value) + public override void WriteValue(Uri? value) { base.WriteValue(value); - AddValue(value, JsonToken.String); + AddJValue(new JValue(value), JsonToken.String); } #endregion @@ -496,7 +502,7 @@ internal override void WriteToken(JsonReader reader, bool writeChildren, bool wr } } - JToken value = tokenReader.CurrentToken.CloneToken(); + JToken value = tokenReader.CurrentToken!.CloneToken(settings: null); if (_parent != null) { diff --git a/Src/Newtonsoft.Json/Linq/JValue.Async.cs b/Src/Newtonsoft.Json/Linq/JValue.Async.cs index 91402d107..e80b880a0 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.Async.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.Async.cs @@ -49,7 +49,7 @@ public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellat { if (converters != null && converters.Length > 0 && _value != null) { - JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); + JsonConverter? matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); if (matchingConverter != null && matchingConverter.CanWrite) { // TODO: Call WriteJsonAsync when it exists. @@ -121,13 +121,13 @@ public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellat return writer.WriteValueAsync(Convert.ToDateTime(_value, CultureInfo.InvariantCulture), cancellationToken); case JTokenType.Bytes: - return writer.WriteValueAsync((byte[])_value, cancellationToken); + return writer.WriteValueAsync((byte[]?)_value, cancellationToken); case JTokenType.Guid: return writer.WriteValueAsync(_value != null ? (Guid?)_value : null, cancellationToken); case JTokenType.TimeSpan: return writer.WriteValueAsync(_value != null ? (TimeSpan?)_value : null, cancellationToken); case JTokenType.Uri: - return writer.WriteValueAsync((Uri)_value, cancellationToken); + return writer.WriteValueAsync((Uri?)_value, cancellationToken); } throw MiscellaneousUtils.CreateArgumentOutOfRangeException(nameof(Type), _valueType, "Unexpected token type."); diff --git a/Src/Newtonsoft.Json/Linq/JValue.cs b/Src/Newtonsoft.Json/Linq/JValue.cs index 85e2473fd..c2f03991c 100644 --- a/Src/Newtonsoft.Json/Linq/JValue.cs +++ b/Src/Newtonsoft.Json/Linq/JValue.cs @@ -28,6 +28,8 @@ using System.Diagnostics; using Newtonsoft.Json.Utilities; using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if HAVE_DYNAMIC using System.Dynamic; using System.Linq.Expressions; @@ -47,14 +49,23 @@ public partial class JValue : JToken, IEquatable, IFormattable, ICompara #endif { private JTokenType _valueType; - private object _value; + private object? _value; - internal JValue(object value, JTokenType type) + internal JValue(object? value, JTokenType type) { _value = value; _valueType = type; } + internal JValue(JValue other, JsonCloneSettings? settings) + : this(other.Value, other.Type) + { + if (settings?.CopyAnnotations ?? true) + { + CopyAnnotations(this, other); + } + } + /// /// Initializes a new instance of the class from another object. /// @@ -69,7 +80,7 @@ public JValue(JValue other) /// /// The value. public JValue(long value) - : this(value, JTokenType.Integer) + : this(BoxedPrimitives.Get(value), JTokenType.Integer) { } @@ -78,7 +89,7 @@ public JValue(long value) /// /// The value. public JValue(decimal value) - : this(value, JTokenType.Float) + : this(BoxedPrimitives.Get(value), JTokenType.Float) { } @@ -106,7 +117,7 @@ public JValue(ulong value) /// /// The value. public JValue(double value) - : this(value, JTokenType.Float) + : this(BoxedPrimitives.Get(value), JTokenType.Float) { } @@ -144,7 +155,7 @@ public JValue(DateTimeOffset value) /// /// The value. public JValue(bool value) - : this(value, JTokenType.Boolean) + : this(BoxedPrimitives.Get(value), JTokenType.Boolean) { } @@ -152,7 +163,7 @@ public JValue(bool value) /// Initializes a new instance of the class with the given value. /// /// The value. - public JValue(string value) + public JValue(string? value) : this(value, JTokenType.String) { } @@ -170,7 +181,7 @@ public JValue(Guid value) /// Initializes a new instance of the class with the given value. /// /// The value. - public JValue(Uri value) + public JValue(Uri? value) : this(value, (value != null) ? JTokenType.Uri : JTokenType.Null) { } @@ -188,7 +199,7 @@ public JValue(TimeSpan value) /// Initializes a new instance of the class with the given value. /// /// The value. - public JValue(object value) + public JValue(object? value) : this(value, GetValueType(null, value)) { } @@ -241,7 +252,7 @@ private static int CompareBigInteger(BigInteger i1, object i2) } #endif - internal static int Compare(JTokenType valueType, object objA, object objB) + internal static int Compare(JTokenType valueType, object? objA, object? objB) { if (objA == objB) { @@ -267,8 +278,8 @@ internal static int Compare(JTokenType valueType, object objA, object objB) } if (objB is BigInteger integerB) { - return -CompareBigInteger(integerB, objA); - } + return -CompareBigInteger(integerB, objA); + } #endif if (objA is ulong || objB is ulong || objA is decimal || objB is decimal) { @@ -300,12 +311,12 @@ internal static int Compare(JTokenType valueType, object objA, object objB) return Convert.ToDecimal(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToDecimal(objB, CultureInfo.InvariantCulture)); } return CompareFloat(objA, objB); - } + } case JTokenType.Comment: case JTokenType.String: case JTokenType.Raw: - string s1 = Convert.ToString(objA, CultureInfo.InvariantCulture); - string s2 = Convert.ToString(objB, CultureInfo.InvariantCulture); + string? s1 = Convert.ToString(objA, CultureInfo.InvariantCulture); + string? s2 = Convert.ToString(objB, CultureInfo.InvariantCulture); return string.CompareOrdinal(s1, s2); case JTokenType.Boolean: @@ -353,10 +364,10 @@ internal static int Compare(JTokenType valueType, object objA, object objB) throw new ArgumentException("Object must be of type byte[]."); } - byte[] bytesA = objA as byte[]; - Debug.Assert(bytesA != null); + byte[]? bytesA = objA as byte[]; + MiscellaneousUtils.Assert(bytesA != null); - return MiscellaneousUtils.ByteArrayCompare(bytesA, bytesB); + return MiscellaneousUtils.ByteArrayCompare(bytesA!, bytesB); case JTokenType.Guid: if (!(objB is Guid)) { @@ -368,7 +379,7 @@ internal static int Compare(JTokenType valueType, object objA, object objB) return guid1.CompareTo(guid2); case JTokenType.Uri: - Uri uri2 = objB as Uri; + Uri? uri2 = objB as Uri; if (uri2 == null) { throw new ArgumentException("Object must be of type Uri."); @@ -407,7 +418,7 @@ private static int CompareFloat(object objA, object objB) } #if HAVE_EXPRESSIONS - private static bool Operation(ExpressionType operation, object objA, object objB, out object result) + private static bool Operation(ExpressionType operation, object? objA, object? objB, out object? result) { if (objA is string || objB is string) { @@ -554,9 +565,9 @@ private static bool Operation(ExpressionType operation, object objA, object objB } #endif - internal override JToken CloneToken() + internal override JToken CloneToken(JsonCloneSettings? settings) { - return new JValue(this); + return new JValue(this, settings); } /// @@ -564,7 +575,7 @@ internal override JToken CloneToken() /// /// The value. /// A comment with the given value. - public static JValue CreateComment(string value) + public static JValue CreateComment(string? value) { return new JValue(value, JTokenType.Comment); } @@ -574,7 +585,7 @@ public static JValue CreateComment(string value) /// /// The value. /// A string with the given value. - public static JValue CreateString(string value) + public static JValue CreateString(string? value) { return new JValue(value, JTokenType.String); } @@ -597,7 +608,7 @@ public static JValue CreateUndefined() return new JValue(null, JTokenType.Undefined); } - private static JTokenType GetValueType(JTokenType? current, object value) + private static JTokenType GetValueType(JTokenType? current, object? value) { if (value == null) { @@ -694,13 +705,13 @@ private static JTokenType GetStringValueType(JTokenType? current) /// Gets or sets the underlying token value. /// /// The underlying token value. - public object Value + public object? Value { get => _value; set { - Type currentType = _value?.GetType(); - Type newType = value?.GetType(); + Type? currentType = _value?.GetType(); + Type? newType = value?.GetType(); if (currentType != newType) { @@ -720,7 +731,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter { if (converters != null && converters.Length > 0 && _value != null) { - JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); + JsonConverter? matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType()); if (matchingConverter != null && matchingConverter.CanWrite) { matchingConverter.WriteJson(writer, _value, JsonSerializer.CreateDefault()); @@ -803,7 +814,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter } return; case JTokenType.Bytes: - writer.WriteValue((byte[])_value); + writer.WriteValue((byte[]?)_value); return; case JTokenType.Guid: writer.WriteValue((_value != null) ? (Guid?)_value : null); @@ -812,7 +823,7 @@ public override void WriteTo(JsonWriter writer, params JsonConverter[] converter writer.WriteValue((_value != null) ? (TimeSpan?)_value : null); return; case JTokenType.Uri: - writer.WriteValue((Uri)_value); + writer.WriteValue((Uri?)_value); return; } @@ -839,7 +850,7 @@ private static bool ValuesEquals(JValue v1, JValue v2) /// true if the current object is equal to the parameter; otherwise, false. /// /// An object to compare with this object. - public bool Equals(JValue other) + public bool Equals(JValue? other) { if (other == null) { @@ -856,9 +867,14 @@ public bool Equals(JValue other) /// /// true if the specified is equal to the current ; otherwise, false. /// - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return Equals(obj as JValue); + if (obj is JValue v) + { + return Equals(v); + } + + return false; } /// @@ -880,6 +896,10 @@ public override int GetHashCode() /// /// Returns a that represents this instance. /// + /// + /// ToString() returns a non-JSON string value for tokens with a type of . + /// If you want the JSON for all token types then you should use . + /// /// /// A that represents this instance. /// @@ -890,7 +910,7 @@ public override string ToString() return string.Empty; } - return _value.ToString(); + return _value.ToString()!; } /// @@ -912,7 +932,7 @@ public string ToString(string format) /// /// A that represents this instance. /// - public string ToString(IFormatProvider formatProvider) + public string ToString(IFormatProvider? formatProvider) { return ToString(null, formatProvider); } @@ -925,7 +945,7 @@ public string ToString(IFormatProvider formatProvider) /// /// A that represents this instance. /// - public string ToString(string format, IFormatProvider formatProvider) + public string ToString(string? format, IFormatProvider? formatProvider) { if (_value == null) { @@ -938,7 +958,7 @@ public string ToString(string format, IFormatProvider formatProvider) } else { - return _value.ToString(); + return _value.ToString()!; } } @@ -957,7 +977,7 @@ protected override DynamicMetaObject GetMetaObject(Expression parameter) private class JValueDynamicProxy : DynamicProxy { - public override bool TryConvert(JValue instance, ConvertBinder binder, out object result) + public override bool TryConvert(JValue instance, ConvertBinder binder, [NotNullWhen(true)]out object? result) { if (binder.Type == typeof(JValue) || binder.Type == typeof(JToken)) { @@ -965,7 +985,7 @@ public override bool TryConvert(JValue instance, ConvertBinder binder, out objec return true; } - object value = instance.Value; + object? value = instance.Value; if (value == null) { @@ -977,9 +997,9 @@ public override bool TryConvert(JValue instance, ConvertBinder binder, out objec return true; } - public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, out object result) + public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, [NotNullWhen(true)]out object? result) { - object compareValue = arg is JValue value ? value.Value : arg; + object? compareValue = arg is JValue value ? value.Value : arg; switch (binder.Operation) { @@ -1023,7 +1043,7 @@ public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder b } #endif - int IComparable.CompareTo(object obj) + int IComparable.CompareTo(object? obj) { if (obj == null) { @@ -1031,7 +1051,7 @@ int IComparable.CompareTo(object obj) } JTokenType comparisonType; - object otherValue; + object? otherValue; if (obj is JValue value) { otherValue = value.Value; @@ -1066,7 +1086,7 @@ int IComparable.CompareTo(object obj) /// /// is not of the same type as this instance. /// - public int CompareTo(JValue obj) + public int CompareTo(JValue? obj) { if (obj == null) { @@ -1096,79 +1116,79 @@ TypeCode IConvertible.GetTypeCode() return TypeCode.Object; } - bool IConvertible.ToBoolean(IFormatProvider provider) + bool IConvertible.ToBoolean(IFormatProvider? provider) { return (bool)this; } - char IConvertible.ToChar(IFormatProvider provider) + char IConvertible.ToChar(IFormatProvider? provider) { return (char)this; } - sbyte IConvertible.ToSByte(IFormatProvider provider) + sbyte IConvertible.ToSByte(IFormatProvider? provider) { return (sbyte)this; } - byte IConvertible.ToByte(IFormatProvider provider) + byte IConvertible.ToByte(IFormatProvider? provider) { return (byte)this; } - short IConvertible.ToInt16(IFormatProvider provider) + short IConvertible.ToInt16(IFormatProvider? provider) { return (short)this; } - ushort IConvertible.ToUInt16(IFormatProvider provider) + ushort IConvertible.ToUInt16(IFormatProvider? provider) { return (ushort)this; } - int IConvertible.ToInt32(IFormatProvider provider) + int IConvertible.ToInt32(IFormatProvider? provider) { return (int)this; } - uint IConvertible.ToUInt32(IFormatProvider provider) + uint IConvertible.ToUInt32(IFormatProvider? provider) { return (uint)this; } - long IConvertible.ToInt64(IFormatProvider provider) + long IConvertible.ToInt64(IFormatProvider? provider) { return (long)this; } - ulong IConvertible.ToUInt64(IFormatProvider provider) + ulong IConvertible.ToUInt64(IFormatProvider? provider) { return (ulong)this; } - float IConvertible.ToSingle(IFormatProvider provider) + float IConvertible.ToSingle(IFormatProvider? provider) { return (float)this; } - double IConvertible.ToDouble(IFormatProvider provider) + double IConvertible.ToDouble(IFormatProvider? provider) { return (double)this; } - decimal IConvertible.ToDecimal(IFormatProvider provider) + decimal IConvertible.ToDecimal(IFormatProvider? provider) { return (decimal)this; } - DateTime IConvertible.ToDateTime(IFormatProvider provider) + DateTime IConvertible.ToDateTime(IFormatProvider? provider) { return (DateTime)this; } - object IConvertible.ToType(Type conversionType, IFormatProvider provider) + object IConvertible.ToType(Type conversionType, IFormatProvider? provider) { - return ToObject(conversionType); + return ToObject(conversionType)!; } #endif } diff --git a/Src/Newtonsoft.Json/Linq/JsonCloneSettings.cs b/Src/Newtonsoft.Json/Linq/JsonCloneSettings.cs new file mode 100644 index 000000000..bad671e43 --- /dev/null +++ b/Src/Newtonsoft.Json/Linq/JsonCloneSettings.cs @@ -0,0 +1,57 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; + +namespace Newtonsoft.Json.Linq +{ + /// + /// Specifies the settings used when cloning JSON. + /// + public class JsonCloneSettings + { + internal static readonly JsonCloneSettings SkipCopyAnnotations = new JsonCloneSettings + { + CopyAnnotations = false + }; + + /// + /// Initializes a new instance of the class. + /// + public JsonCloneSettings() + { + CopyAnnotations = true; + } + + /// + /// Gets or sets a flag that indicates whether to copy annotations when cloning a . + /// The default value is true. + /// + /// + /// A flag that indicates whether to copy annotations when cloning a . + /// + public bool CopyAnnotations { get; set; } + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs b/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs index 64aba4c10..2c224ac2d 100644 --- a/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs +++ b/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs @@ -1,4 +1,29 @@ -using System; +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; namespace Newtonsoft.Json.Linq { diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs index c6cb1e889..0378713d5 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/ArrayIndexFilter.cs @@ -8,13 +8,13 @@ internal class ArrayIndexFilter : PathFilter { public int? Index { get; set; } - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { if (Index != null) { - JToken v = GetTokenIndex(t, errorWhenNoMatch, Index.GetValueOrDefault()); + JToken? v = GetTokenIndex(t, settings, Index.GetValueOrDefault()); if (v != null) { @@ -32,7 +32,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable Indexes { get; set; } + internal List Indexes; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public ArrayMultipleIndexFilter(List indexes) + { + Indexes = indexes; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { foreach (int i in Indexes) { - JToken v = GetTokenIndex(t, errorWhenNoMatch, i); + JToken? v = GetTokenIndex(t, settings, i); if (v != null) { diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs index e6ee0b7b5..c948b5e06 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs @@ -11,7 +11,7 @@ internal class ArraySliceFilter : PathFilter public int? End { get; set; } public int? Step { get; set; } - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { if (Step == 0) { @@ -56,7 +56,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public FieldFilter(string? name) + { + Name = name; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { @@ -16,28 +21,28 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable p in o) + foreach (KeyValuePair p in o) { - yield return p.Value; + yield return p.Value!; } } } else { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Property '{0}' not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, Name ?? "*", t.GetType().Name)); } diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs index 3d46708e4..c3eb7033a 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/FieldMultipleFilter.cs @@ -11,9 +11,14 @@ namespace Newtonsoft.Json.Linq.JsonPath { internal class FieldMultipleFilter : PathFilter { - public List Names { get; set; } + internal List Names; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public FieldMultipleFilter(List names) + { + Names = names; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { @@ -21,14 +26,14 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable "'" + n + "'") #if !HAVE_STRING_JOIN_WITH_ENUMERABLE diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs b/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs index b61ec4c7a..c29fcd063 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/JPath.cs @@ -107,7 +107,7 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool case '(': if (_currentIndex > currentPartStartIndex) { - string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); + string? member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); if (member == "*") { member = null; @@ -118,6 +118,8 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool } filters.Add(ParseIndexer(currentChar, scan)); + scan = false; + _currentIndex++; currentPartStartIndex = _currentIndex; followingIndexer = true; @@ -136,7 +138,7 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool case '.': if (_currentIndex > currentPartStartIndex) { - string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); + string? member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex); if (member == "*") { member = null; @@ -177,7 +179,7 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool if (_currentIndex > currentPartStartIndex) { - string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex).TrimEnd(); + string? member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex).TrimEnd(); if (member == "*") { member = null; @@ -196,9 +198,9 @@ private bool ParsePath(List filters, int currentPartStartIndex, bool return atPathEnd; } - private static PathFilter CreatePathFilter(string member, bool scan) + private static PathFilter CreatePathFilter(string? member, bool scan) { - PathFilter filter = (scan) ? (PathFilter)new ScanFilter {Name = member} : new FieldFilter {Name = member}; + PathFilter filter = (scan) ? (PathFilter)new ScanFilter(member) : new FieldFilter(member); return filter; } @@ -230,7 +232,7 @@ private PathFilter ParseArrayIndexer(char indexerCloseChar) { int start = _currentIndex; int? end = null; - List indexes = null; + List? indexes = null; int colonCount = 0; int? startIndex = null; int? endIndex = null; @@ -262,7 +264,7 @@ private PathFilter ParseArrayIndexer(char indexerCloseChar) int index = Convert.ToInt32(indexer, CultureInfo.InvariantCulture); indexes.Add(index); - return new ArrayMultipleIndexFilter { Indexes = indexes }; + return new ArrayMultipleIndexFilter(indexes); } else if (colonCount > 0) { @@ -421,26 +423,19 @@ private PathFilter ParseQuery(char indexerCloseChar, bool scan) if (!scan) { - return new QueryFilter - { - Expression = expression - }; + return new QueryFilter(expression); } else { - return new QueryScanFilter - { - Expression = expression - }; + return new QueryScanFilter(expression); } } - private bool TryParseExpression(out List expressionPath) + private bool TryParseExpression(out List? expressionPath) { if (_expression[_currentIndex] == '$') { - expressionPath = new List(); - expressionPath.Add(RootFilter.Instance); + expressionPath = new List { RootFilter.Instance }; } else if (_expression[_currentIndex] == '@') { @@ -454,7 +449,7 @@ private bool TryParseExpression(out List expressionPath) _currentIndex++; - if (ParsePath(expressionPath, _currentIndex, true)) + if (ParsePath(expressionPath!, _currentIndex, true)) { throw new JsonException("Path ended with open query."); } @@ -471,12 +466,12 @@ private object ParseSide() { EatWhitespace(); - if (TryParseExpression(out var expressionPath)) + if (TryParseExpression(out List? expressionPath)) { EatWhitespace(); EnsureLength("Path ended with open query."); - return expressionPath; + return expressionPath!; } if (TryParseValue(out var value)) @@ -492,13 +487,13 @@ private object ParseSide() private QueryExpression ParseExpression() { - QueryExpression rootExpression = null; - CompositeExpression parentExpression = null; + QueryExpression? rootExpression = null; + CompositeExpression? parentExpression = null; while (_currentIndex < _expression.Length) { object left = ParseSide(); - object right = null; + object? right = null; QueryOperator op; if (_expression[_currentIndex] == ')' @@ -514,19 +509,14 @@ private QueryExpression ParseExpression() right = ParseSide(); } - BooleanQueryExpression booleanExpression = new BooleanQueryExpression - { - Left = left, - Operator = op, - Right = right - }; + BooleanQueryExpression booleanExpression = new BooleanQueryExpression(op, left, right); if (_expression[_currentIndex] == ')') { if (parentExpression != null) { parentExpression.Expressions.Add(booleanExpression); - return rootExpression; + return rootExpression!; } return booleanExpression; @@ -540,7 +530,7 @@ private QueryExpression ParseExpression() if (parentExpression == null || parentExpression.Operator != QueryOperator.And) { - CompositeExpression andExpression = new CompositeExpression { Operator = QueryOperator.And }; + CompositeExpression andExpression = new CompositeExpression(QueryOperator.And); parentExpression?.Expressions.Add(andExpression); @@ -563,7 +553,7 @@ private QueryExpression ParseExpression() if (parentExpression == null || parentExpression.Operator != QueryOperator.Or) { - CompositeExpression orExpression = new CompositeExpression { Operator = QueryOperator.Or }; + CompositeExpression orExpression = new CompositeExpression(QueryOperator.Or); parentExpression?.Expressions.Add(orExpression); @@ -582,7 +572,7 @@ private QueryExpression ParseExpression() throw new JsonException("Path ended with open query."); } - private bool TryParseValue(out object value) + private bool TryParseValue(out object? value) { char currentChar = _expression[_currentIndex]; if (currentChar == '\'') @@ -763,9 +753,9 @@ private string ReadRegexString() private bool Match(string s) { int currentPosition = _currentIndex; - foreach (char c in s) + for (int i = 0; i < s.Length; i++) { - if (currentPosition < _expression.Length && _expression[currentPosition] == c) + if (currentPosition < _expression.Length && _expression[currentPosition] == s[i]) { currentPosition++; } @@ -832,7 +822,7 @@ private QueryOperator ParseOperator() private PathFilter ParseQuotedField(char indexerCloseChar, bool scan) { - List fields = null; + List? fields = null; while (_currentIndex < _expression.Length) { @@ -847,8 +837,8 @@ private PathFilter ParseQuotedField(char indexerCloseChar, bool scan) { fields.Add(field); return (scan) - ? (PathFilter)new ScanMultipleFilter { Names = fields } - : (PathFilter)new FieldMultipleFilter { Names = fields }; + ? (PathFilter)new ScanMultipleFilter(fields) + : (PathFilter)new FieldMultipleFilter(fields); } else { @@ -884,17 +874,17 @@ private void EnsureLength(string message) } } - internal IEnumerable Evaluate(JToken root, JToken t, bool errorWhenNoMatch) + internal IEnumerable Evaluate(JToken root, JToken t, JsonSelectSettings? settings) { - return Evaluate(Filters, root, t, errorWhenNoMatch); + return Evaluate(Filters, root, t, settings); } - internal static IEnumerable Evaluate(List filters, JToken root, JToken t, bool errorWhenNoMatch) + internal static IEnumerable Evaluate(List filters, JToken root, JToken t, JsonSelectSettings? settings) { IEnumerable current = new[] { t }; foreach (PathFilter filter in filters) { - current = filter.ExecuteFilter(root, current, errorWhenNoMatch); + current = filter.ExecuteFilter(root, current, settings); } return current; diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs index 6ea77c550..45a1683e9 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/PathFilter.cs @@ -6,16 +6,15 @@ namespace Newtonsoft.Json.Linq.JsonPath { internal abstract class PathFilter { - public abstract IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch); + public abstract IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings); - protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index) + protected static JToken? GetTokenIndex(JToken t, JsonSelectSettings? settings, int index) { - if (t is JArray a) { if (a.Count <= index) { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Index {0} outside the bounds of JArray.".FormatWith(CultureInfo.InvariantCulture, index)); } @@ -29,7 +28,7 @@ protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index { if (c.Count <= index) { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Index {0} outside the bounds of JConstructor.".FormatWith(CultureInfo.InvariantCulture, index)); } @@ -41,7 +40,7 @@ protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index } else { - if (errorWhenNoMatch) + if (settings?.ErrorWhenNoMatch ?? false) { throw new JsonException("Index {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, index, t.GetType().Name)); } @@ -50,7 +49,7 @@ protected static JToken GetTokenIndex(JToken t, bool errorWhenNoMatch, int index } } - protected static JToken GetNextScanValue(JToken originalParent, JToken container, JToken value) + protected static JToken? GetNextScanValue(JToken originalParent, JToken? container, JToken? value) { // step into container's values if (container != null && container.HasValues) @@ -60,7 +59,7 @@ protected static JToken GetNextScanValue(JToken originalParent, JToken container else { // finished container, move to parent - while (value != null && value != originalParent && value == value.Parent.Last) + while (value != null && value != originalParent && value == value.Parent!.Last) { value = value.Parent; } diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs index a65bcbfbd..617a7c419 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryExpression.cs @@ -32,28 +32,39 @@ internal enum QueryOperator internal abstract class QueryExpression { - public QueryOperator Operator { get; set; } + internal QueryOperator Operator; - public abstract bool IsMatch(JToken root, JToken t); + public QueryExpression(QueryOperator @operator) + { + Operator = @operator; + } + + // For unit tests + public bool IsMatch(JToken root, JToken t) + { + return IsMatch(root, t, null); + } + + public abstract bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings); } internal class CompositeExpression : QueryExpression { public List Expressions { get; set; } - public CompositeExpression() + public CompositeExpression(QueryOperator @operator) : base(@operator) { Expressions = new List(); } - public override bool IsMatch(JToken root, JToken t) + public override bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings) { switch (Operator) { case QueryOperator.And: foreach (QueryExpression e in Expressions) { - if (!e.IsMatch(root, t)) + if (!e.IsMatch(root, t, settings)) { return false; } @@ -62,7 +73,7 @@ public override bool IsMatch(JToken root, JToken t) case QueryOperator.Or: foreach (QueryExpression e in Expressions) { - if (e.IsMatch(root, t)) + if (e.IsMatch(root, t, settings)) { return true; } @@ -76,10 +87,16 @@ public override bool IsMatch(JToken root, JToken t) internal class BooleanQueryExpression : QueryExpression { - public object Left { get; set; } - public object Right { get; set; } + public readonly object Left; + public readonly object? Right; - private IEnumerable GetResult(JToken root, JToken t, object o) + public BooleanQueryExpression(QueryOperator @operator, object left, object? right) : base(@operator) + { + Left = left; + Right = right; + } + + private IEnumerable GetResult(JToken root, JToken t, object? o) { if (o is JToken resultToken) { @@ -88,13 +105,13 @@ private IEnumerable GetResult(JToken root, JToken t, object o) if (o is List pathFilters) { - return JPath.Evaluate(pathFilters, root, t, false); + return JPath.Evaluate(pathFilters, root, t, null); } return CollectionUtils.ArrayEmpty(); } - public override bool IsMatch(JToken root, JToken t) + public override bool IsMatch(JToken root, JToken t, JsonSelectSettings? settings) { if (Operator == QueryOperator.Exists) { @@ -113,7 +130,7 @@ public override bool IsMatch(JToken root, JToken t) JToken leftResult = leftResults.Current; foreach (JToken rightResult in rightResults) { - if (MatchTokens(leftResult, rightResult)) + if (MatchTokens(leftResult, rightResult, settings)) { return true; } @@ -125,14 +142,14 @@ public override bool IsMatch(JToken root, JToken t) return false; } - private bool MatchTokens(JToken leftResult, JToken rightResult) + private bool MatchTokens(JToken leftResult, JToken rightResult, JsonSelectSettings? settings) { if (leftResult is JValue leftValue && rightResult is JValue rightValue) { switch (Operator) { case QueryOperator.RegexEquals: - if (RegexEquals(leftValue, rightValue)) + if (RegexEquals(leftValue, rightValue, settings)) { return true; } @@ -204,20 +221,25 @@ private bool MatchTokens(JToken leftResult, JToken rightResult) return false; } - private static bool RegexEquals(JValue input, JValue pattern) + private static bool RegexEquals(JValue input, JValue pattern, JsonSelectSettings? settings) { if (input.Type != JTokenType.String || pattern.Type != JTokenType.String) { return false; } - string regexText = (string)pattern.Value; + string regexText = (string)pattern.Value!; int patternOptionDelimiterIndex = regexText.LastIndexOf('/'); string patternText = regexText.Substring(1, patternOptionDelimiterIndex - 1); string optionsText = regexText.Substring(patternOptionDelimiterIndex + 1); - return Regex.IsMatch((string)input.Value, patternText, MiscellaneousUtils.GetRegexOptions(optionsText)); +#if HAVE_REGEX_TIMEOUTS + TimeSpan timeout = settings?.RegexMatchTimeout ?? Regex.InfiniteMatchTimeout; + return Regex.IsMatch((string)input.Value!, patternText, MiscellaneousUtils.GetRegexOptions(optionsText), timeout); +#else + return Regex.IsMatch((string)input.Value!, patternText, MiscellaneousUtils.GetRegexOptions(optionsText)); +#endif } internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) @@ -240,7 +262,7 @@ internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) return false; } - string queryValueString = (string)queryValue.Value; + string queryValueString = (string)queryValue.Value!; string currentValueString; @@ -258,21 +280,21 @@ internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) else #endif { - DateTimeUtils.WriteDateTimeString(writer, (DateTime)value.Value, DateFormatHandling.IsoDateFormat, null, CultureInfo.InvariantCulture); + DateTimeUtils.WriteDateTimeString(writer, (DateTime)value.Value!, DateFormatHandling.IsoDateFormat, null, CultureInfo.InvariantCulture); } currentValueString = writer.ToString(); } break; case JTokenType.Bytes: - currentValueString = Convert.ToBase64String((byte[])value.Value); + currentValueString = Convert.ToBase64String((byte[])value.Value!); break; case JTokenType.Guid: case JTokenType.TimeSpan: - currentValueString = value.Value.ToString(); + currentValueString = value.Value!.ToString()!; break; case JTokenType.Uri: - currentValueString = ((Uri)value.Value).OriginalString; + currentValueString = ((Uri)value.Value!).OriginalString; break; default: return false; @@ -283,8 +305,8 @@ internal static bool EqualsWithStringCoercion(JValue value, JValue queryValue) internal static bool EqualsWithStrictMatch(JValue value, JValue queryValue) { - Debug.Assert(value != null); - Debug.Assert(queryValue != null); + MiscellaneousUtils.Assert(value != null); + MiscellaneousUtils.Assert(queryValue != null); // Handle comparing an integer with a float // e.g. Comparing 1 and 1.0 diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs index 775acd808..e844e113f 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryFilter.cs @@ -5,15 +5,20 @@ namespace Newtonsoft.Json.Linq.JsonPath { internal class QueryFilter : PathFilter { - public QueryExpression Expression { get; set; } + internal QueryExpression Expression; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public QueryFilter(QueryExpression expression) + { + Expression = expression; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { foreach (JToken v in t) { - if (Expression.IsMatch(root, v)) + if (Expression.IsMatch(root, v, settings)) { yield return v; } diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs index 027d02101..a1b5270ac 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/QueryScanFilter.cs @@ -5,9 +5,14 @@ namespace Newtonsoft.Json.Linq.JsonPath { internal class QueryScanFilter : PathFilter { - public QueryExpression Expression { get; set; } + internal QueryExpression Expression; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public QueryScanFilter(QueryExpression expression) + { + Expression = expression; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken t in current) { @@ -15,7 +20,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { return new[] { root }; } diff --git a/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs b/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs index 073edd9d0..a3f6adcc3 100644 --- a/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs +++ b/Src/Newtonsoft.Json/Linq/JsonPath/ScanFilter.cs @@ -4,9 +4,14 @@ namespace Newtonsoft.Json.Linq.JsonPath { internal class ScanFilter : PathFilter { - public string Name { get; set; } + internal string? Name; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public ScanFilter(string? name) + { + Name = name; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken c in current) { @@ -15,11 +20,11 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable Names { get; set; } + private List _names; - public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, bool errorWhenNoMatch) + public ScanMultipleFilter(List names) + { + _names = names; + } + + public override IEnumerable ExecuteFilter(JToken root, IEnumerable current, JsonSelectSettings? settings) { foreach (JToken c in current) { - JToken value = c; + JToken? value = c; while (true) { - JContainer container = value as JContainer; + JContainer? container = value as JContainer; value = GetNextScanValue(c, container, value); if (value == null) @@ -24,7 +29,7 @@ public override IEnumerable ExecuteFilter(JToken root, IEnumerable ExecuteFilter(JToken root, IEnumerable + /// Specifies the settings used when selecting JSON. + /// + public class JsonSelectSettings + { +#if HAVE_REGEX_TIMEOUTS + /// + /// Gets or sets a timeout that will be used when executing regular expressions. + /// + /// The timeout that will be used when executing regular expressions. + public TimeSpan? RegexMatchTimeout { get; set; } +#endif + + /// + /// Gets or sets a flag that indicates whether an error should be thrown if + /// no tokens are found when evaluating part of the expression. + /// + /// + /// A flag that indicates whether an error should be thrown if + /// no tokens are found when evaluating part of the expression. + /// + public bool ErrorWhenNoMatch { get; set; } + } +} diff --git a/Src/Newtonsoft.Json/Linq/MergeArrayHandling.cs b/Src/Newtonsoft.Json/Linq/MergeArrayHandling.cs index 5e7fadf12..c4cd8d72b 100644 --- a/Src/Newtonsoft.Json/Linq/MergeArrayHandling.cs +++ b/Src/Newtonsoft.Json/Linq/MergeArrayHandling.cs @@ -1,3 +1,28 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + namespace Newtonsoft.Json.Linq { /// diff --git a/Src/Newtonsoft.Json/Linq/MergeNullValueHandling.cs b/Src/Newtonsoft.Json/Linq/MergeNullValueHandling.cs index 30d3d845d..1e41585b1 100644 --- a/Src/Newtonsoft.Json/Linq/MergeNullValueHandling.cs +++ b/Src/Newtonsoft.Json/Linq/MergeNullValueHandling.cs @@ -1,4 +1,29 @@ -using System; +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using System; namespace Newtonsoft.Json.Linq { diff --git a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj index 12e589b8f..47c63018e 100644 --- a/Src/Newtonsoft.Json/Newtonsoft.Json.csproj +++ b/Src/Newtonsoft.Json/Newtonsoft.Json.csproj @@ -1,8 +1,8 @@  - net45;net40;net35;net20;netstandard1.0;netstandard1.3;netstandard2.0;portable-net45+win8+wpa81+wp8;portable-net40+win8+wpa81+wp8+sl5 + net6.0;net45;net40;net35;net20;netstandard1.0;netstandard1.3;netstandard2.0 $(LibraryFrameworks) - latest + 9.0 11.0.0.0 11.0.1 @@ -18,6 +18,8 @@ Json.NET Newtonsoft.Json json + README.md + packageIcon.png https://www.newtonsoft.com/content/images/nugeticon.png https://www.newtonsoft.com/json MIT @@ -25,22 +27,37 @@ Newtonsoft.Json Newtonsoft.Json true + enable 2.12 true snupkg Newtonsoft.Json.ruleset + true + + true + 13.0.1 + + $(NoWarn);CP0003 + + - - - + + + + + Json.NET .NET 6.0 + HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_ASYNC_DISPOSABLE;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_REGEX_TIMEOUTS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;HAVE_INDEXOF_STRING_COMPARISON;HAVE_REPLACE_STRING_COMPARISON;HAVE_REPLACE_STRING_COMPARISON;HAVE_GETHASHCODE_STRING_COMPARISON;HAVE_NULLABLE_ATTRIBUTES;HAVE_DYNAMIC_CODE_COMPILED;HAS_ARRAY_EMPTY;HAVE_DATE_ONLY;$(AdditionalConstants) + - Json.NET - HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) + Json.NET .NET 4.5 + HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_EMIT;HAVE_REGEX_TIMEOUTS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) Json.NET .NET 4.0 @@ -55,42 +72,24 @@ NET20;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CAS;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_DB_NULL_TYPE_CODE;HAVE_EMPTY_TYPES;HAVE_FAST_REVERSE;HAVE_FULL_REFLECTION;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_MEMORY_BARRIER;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_REFLECTION_EMIT;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;$(AdditionalConstants) - - - + + + Json.NET .NET Standard 1.0 - NETSTANDARD1_0;PORTABLE;HAVE_ASYNC;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;$(AdditionalConstants) + NETSTANDARD1_0;PORTABLE;HAVE_ASYNC;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) - - + + Json.NET .NET Standard 1.3 - NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;HAVE_CONCURRENT_DICTIONARY;HAVE_ICONVERTIBLE;$(AdditionalConstants) + NETSTANDARD1_3;PORTABLE;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_SERIALIZATION;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_XML_DOCUMENT;HAVE_CONCURRENT_DICTIONARY;HAVE_ICONVERTIBLE;HAVE_REGEX_TIMEOUTS;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) Json.NET .NET Standard 2.0 - NETSTANDARD2_0;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;$(AdditionalConstants) - - - Json.NET Portable .NET 4.0 - PORTABLE40;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;$(AdditionalConstants) - .NETPortable - v4.0 - Profile328 - .NETPortable,Version=v0.0,Profile=Profile328 - $(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets - - - Json.NET Portable - PORTABLE;HAVE_ASYNC;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DYNAMIC;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_GUID_TRY_PARSE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_ISET;HAVE_LINQ;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_REFLECTION_BINDER;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE;$(AdditionalConstants) - .NETPortable - v4.5 - Profile259 - .NETPortable,Version=v0.0,Profile=Profile259 - $(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets + NETSTANDARD2_0;HAVE_ADO_NET;HAVE_APP_DOMAIN;HAVE_ASYNC;HAVE_BIG_INTEGER;HAVE_BINARY_FORMATTER;HAVE_BINARY_SERIALIZATION;HAVE_BINARY_EXCEPTION_SERIALIZATION;HAVE_CHAR_TO_LOWER_WITH_CULTURE;HAVE_CHAR_TO_STRING_WITH_CULTURE;HAVE_COM_ATTRIBUTES;HAVE_COMPONENT_MODEL;HAVE_CONCURRENT_COLLECTIONS;HAVE_COVARIANT_GENERICS;HAVE_DATA_CONTRACTS;HAVE_DATE_TIME_OFFSET;HAVE_DB_NULL_TYPE_CODE;HAVE_DYNAMIC;HAVE_EMPTY_TYPES;HAVE_ENTITY_FRAMEWORK;HAVE_EXPRESSIONS;HAVE_FAST_REVERSE;HAVE_FSHARP_TYPES;HAVE_FULL_REFLECTION;HAVE_GUID_TRY_PARSE;HAVE_HASH_SET;HAVE_ICLONEABLE;HAVE_ICONVERTIBLE;HAVE_IGNORE_DATA_MEMBER_ATTRIBUTE;HAVE_INOTIFY_COLLECTION_CHANGED;HAVE_INOTIFY_PROPERTY_CHANGING;HAVE_ISET;HAVE_LINQ;HAVE_MEMORY_BARRIER;HAVE_METHOD_IMPL_ATTRIBUTE;HAVE_NON_SERIALIZED_ATTRIBUTE;HAVE_READ_ONLY_COLLECTIONS;HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE;HAVE_SERIALIZATION_BINDER_BIND_TO_NAME;HAVE_STREAM_READER_WRITER_CLOSE;HAVE_STRING_JOIN_WITH_ENUMERABLE;HAVE_TIME_SPAN_PARSE_WITH_CULTURE;HAVE_TIME_SPAN_TO_STRING_WITH_CULTURE;HAVE_TIME_ZONE_INFO;HAVE_TRACE_WRITER;HAVE_TYPE_DESCRIPTOR;HAVE_UNICODE_SURROGATE_DETECTION;HAVE_VARIANT_TYPE_PARAMETERS;HAVE_VERSION_TRY_PARSE;HAVE_XLINQ;HAVE_XML_DOCUMENT;HAVE_XML_DOCUMENT_TYPE;HAVE_CONCURRENT_DICTIONARY;HAVE_REGEX_TIMEOUTS;$(AdditionalConstants) \ No newline at end of file diff --git a/Src/Newtonsoft.Json/README.md b/Src/Newtonsoft.Json/README.md new file mode 100644 index 000000000..9982a45ca --- /dev/null +++ b/Src/Newtonsoft.Json/README.md @@ -0,0 +1,71 @@ +# ![Logo](https://raw.githubusercontent.com/JamesNK/Newtonsoft.Json/master/Doc/icons/logo.jpg) Json.NET + +[![NuGet version (Newtonsoft.Json)](https://img.shields.io/nuget/v/Newtonsoft.Json.svg?style=flat-square)](https://www.nuget.org/packages/Newtonsoft.Json/) +[![Build status](https://dev.azure.com/jamesnk/Public/_apis/build/status/JamesNK.Newtonsoft.Json?branchName=master)](https://dev.azure.com/jamesnk/Public/_build/latest?definitionId=8) + +Json.NET is a popular high-performance JSON framework for .NET + +## Serialize JSON + +```csharp +Product product = new Product(); +product.Name = "Apple"; +product.Expiry = new DateTime(2008, 12, 28); +product.Sizes = new string[] { "Small" }; + +string json = JsonConvert.SerializeObject(product); +// { +// "Name": "Apple", +// "Expiry": "2008-12-28T00:00:00", +// "Sizes": [ +// "Small" +// ] +// } +``` + +## Deserialize JSON + +```csharp +string json = @"{ + 'Name': 'Bad Boys', + 'ReleaseDate': '1995-4-7T00:00:00', + 'Genres': [ + 'Action', + 'Comedy' + ] +}"; + +Movie m = JsonConvert.DeserializeObject(json); + +string name = m.Name; +// Bad Boys +``` + +## LINQ to JSON + +```csharp +JArray array = new JArray(); +array.Add("Manual text"); +array.Add(new DateTime(2000, 5, 23)); + +JObject o = new JObject(); +o["MyArray"] = array; + +string json = o.ToString(); +// { +// "MyArray": [ +// "Manual text", +// "2000-05-23T00:00:00" +// ] +// } +``` + +## Links + +- [Homepage](https://www.newtonsoft.com/json) +- [Documentation](https://www.newtonsoft.com/json/help) +- [NuGet Package](https://www.nuget.org/packages/Newtonsoft.Json) +- [Release Notes](https://github.com/JamesNK/Newtonsoft.Json/releases) +- [Contributing Guidelines](https://github.com/JamesNK/Newtonsoft.Json/blob/master/CONTRIBUTING.md) +- [License](https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md) +- [Stack Overflow](https://stackoverflow.com/questions/tagged/json.net) diff --git a/Src/Newtonsoft.Json/Schema/Extensions.cs b/Src/Newtonsoft.Json/Schema/Extensions.cs index 4b9d2db7a..df8ffbaaf 100644 --- a/Src/Newtonsoft.Json/Schema/Extensions.cs +++ b/Src/Newtonsoft.Json/Schema/Extensions.cs @@ -28,6 +28,8 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json.Utilities; +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Schema/JsonSchema.cs b/Src/Newtonsoft.Json/Schema/JsonSchema.cs index e7cf44198..034bd0634 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchema.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchema.cs @@ -30,6 +30,8 @@ using Newtonsoft.Json.Utilities; using System.Globalization; +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs index 310ef70a1..b506565db 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaBuilder.cs @@ -35,6 +35,8 @@ using Newtonsoft.Json.Utilities; using Newtonsoft.Json.Linq; +#nullable disable + namespace Newtonsoft.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] @@ -87,7 +89,10 @@ internal JsonSchema Read(JsonReader reader) private string UnescapeReference(string reference) { - return Uri.UnescapeDataString(reference).Replace("~1", "/").Replace("~0", "~"); + string unescapedReference = Uri.UnescapeDataString(reference); + unescapedReference = StringUtils.Replace(unescapedReference, "~1", "/"); + unescapedReference = StringUtils.Replace(unescapedReference, "~0", "~"); + return unescapedReference; } private JsonSchema ResolveReferences(JsonSchema schema) @@ -218,8 +223,12 @@ private JsonSchema BuildSchema(JToken token) return deferredSchema; } - string location = token.Path.Replace(".", "/").Replace("[", "/").Replace("]", string.Empty); - if (!string.IsNullOrEmpty(location)) + string location = token.Path; + location = StringUtils.Replace(location, ".", "/"); + location = StringUtils.Replace(location, "[", "/"); + location = StringUtils.Replace(location, "]", string.Empty); + + if (!StringUtils.IsNullOrEmpty(location)) { location = "/" + location; } diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs index ab41d34e7..d43939416 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaConstants.cs @@ -26,6 +26,8 @@ using System; using System.Collections.Generic; +#nullable disable + namespace Newtonsoft.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs index b1b53628f..2349589d2 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaException.cs @@ -26,6 +26,8 @@ using System; using System.Runtime.Serialization; +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs index ba8245b0c..7cdab6111 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaGenerator.cs @@ -37,6 +37,8 @@ #endif +#nullable disable + namespace Newtonsoft.Json.Schema { /// @@ -173,7 +175,7 @@ private string GetTitle(Type type) { JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(type); - if (!string.IsNullOrEmpty(containerAttribute?.Title)) + if (!StringUtils.IsNullOrEmpty(containerAttribute?.Title)) { return containerAttribute.Title; } @@ -185,7 +187,7 @@ private string GetDescription(Type type) { JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(type); - if (!string.IsNullOrEmpty(containerAttribute?.Description)) + if (!StringUtils.IsNullOrEmpty(containerAttribute?.Description)) { return containerAttribute.Description; } @@ -202,7 +204,7 @@ private string GetTypeId(Type type, bool explicitOnly) { JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(type); - if (!string.IsNullOrEmpty(containerAttribute?.Id)) + if (!StringUtils.IsNullOrEmpty(containerAttribute?.Id)) { return containerAttribute.Id; } @@ -230,7 +232,7 @@ private JsonSchema GenerateInternal(Type type, Required valueRequired, bool requ string resolvedId = GetTypeId(type, false); string explicitId = GetTypeId(type, true); - if (!string.IsNullOrEmpty(resolvedId)) + if (!StringUtils.IsNullOrEmpty(resolvedId)) { JsonSchema resolvedSchema = _resolver.GetSchema(resolvedId); if (resolvedSchema != null) diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs index af01626d9..2c55d075a 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaModel.cs @@ -28,6 +28,8 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json.Utilities; +#nullable disable + namespace Newtonsoft.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs index 648206a7d..e29d42e8e 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaModelBuilder.cs @@ -32,6 +32,8 @@ #endif +#nullable disable + namespace Newtonsoft.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs index a01a47db0..30757f0ba 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaNode.cs @@ -33,6 +33,8 @@ #endif +#nullable disable + namespace Newtonsoft.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaNodeCollection.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaNodeCollection.cs index db45fac47..af5bbb7ed 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaNodeCollection.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaNodeCollection.cs @@ -26,6 +26,8 @@ using System; using System.Collections.ObjectModel; +#nullable disable + namespace Newtonsoft.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaResolver.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaResolver.cs index 4780d4b20..714aebd6f 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaResolver.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaResolver.cs @@ -32,6 +32,8 @@ #endif +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaType.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaType.cs index 31ad683af..ec9181b12 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaType.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaType.cs @@ -25,6 +25,8 @@ using System; +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs b/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs index c17f7a6f3..c5843bedd 100644 --- a/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs +++ b/Src/Newtonsoft.Json/Schema/JsonSchemaWriter.cs @@ -35,6 +35,8 @@ #endif +#nullable disable + namespace Newtonsoft.Json.Schema { [Obsolete("JSON Schema validation has been moved to its own package. See https://www.newtonsoft.com/jsonschema for more details.")] diff --git a/Src/Newtonsoft.Json/Schema/UndefinedSchemaIdHandling.cs b/Src/Newtonsoft.Json/Schema/UndefinedSchemaIdHandling.cs index 0f6aa4ba6..9064700df 100644 --- a/Src/Newtonsoft.Json/Schema/UndefinedSchemaIdHandling.cs +++ b/Src/Newtonsoft.Json/Schema/UndefinedSchemaIdHandling.cs @@ -25,6 +25,8 @@ using System; +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Schema/ValidationEventArgs.cs b/Src/Newtonsoft.Json/Schema/ValidationEventArgs.cs index 5d69c1fb0..180053988 100644 --- a/Src/Newtonsoft.Json/Schema/ValidationEventArgs.cs +++ b/Src/Newtonsoft.Json/Schema/ValidationEventArgs.cs @@ -26,6 +26,8 @@ using System; using Newtonsoft.Json.Utilities; +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Schema/ValidationEventHandler.cs b/Src/Newtonsoft.Json/Schema/ValidationEventHandler.cs index a287e8b43..cdeaed2b3 100644 --- a/Src/Newtonsoft.Json/Schema/ValidationEventHandler.cs +++ b/Src/Newtonsoft.Json/Schema/ValidationEventHandler.cs @@ -25,6 +25,8 @@ using System; +#nullable disable + namespace Newtonsoft.Json.Schema { /// diff --git a/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs b/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs index 0645631d2..406975941 100644 --- a/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs +++ b/Src/Newtonsoft.Json/Serialization/CachedAttributeGetter.cs @@ -31,9 +31,9 @@ namespace Newtonsoft.Json.Serialization { internal static class CachedAttributeGetter where T : Attribute { - private static readonly ThreadSafeStore TypeAttributeCache = new ThreadSafeStore(JsonTypeReflector.GetAttribute); + private static readonly ThreadSafeStore TypeAttributeCache = new ThreadSafeStore(JsonTypeReflector.GetAttribute); - public static T GetAttribute(object type) + public static T? GetAttribute(object type) { return TypeAttributeCache.Get(type); } diff --git a/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs b/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs index c0107cfdc..554e89a57 100644 --- a/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs @@ -37,7 +37,7 @@ public class CamelCasePropertyNamesContractResolver : DefaultContractResolver { private static readonly object TypeContractCacheLock = new object(); private static readonly DefaultJsonNameTable NameTable = new DefaultJsonNameTable(); - private static Dictionary, JsonContract> _contractCache; + private static Dictionary, JsonContract>? _contractCache; /// /// Initializes a new instance of the class. @@ -65,8 +65,8 @@ public override JsonContract ResolveContract(Type type) // for backwards compadibility the CamelCasePropertyNamesContractResolver shares contracts between instances StructMultiKey key = new StructMultiKey(GetType(), type); - Dictionary, JsonContract> cache = _contractCache; - if (cache == null || !cache.TryGetValue(key, out JsonContract contract)) + Dictionary, JsonContract>? cache = _contractCache; + if (cache == null || !cache.TryGetValue(key, out JsonContract? contract)) { contract = CreateContract(type); diff --git a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs index a3b934b8d..94bf51085 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs @@ -168,7 +168,7 @@ public class DefaultContractResolver : IContractResolver /// Gets or sets the naming strategy used to resolve how property names and dictionary keys are serialized. /// /// The naming strategy used to resolve how property names and dictionary keys are serialized. - public NamingStrategy NamingStrategy { get; set; } + public NamingStrategy? NamingStrategy { get; set; } /// /// Initializes a new instance of the class. @@ -233,18 +233,21 @@ protected virtual List GetSerializableMembers(Type objectType) MemberSerialization memberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType, ignoreSerializableAttribute); + // Exclude index properties + // Do not filter ByRef types here because accessing FieldType/PropertyType can trigger additonal assembly loads IEnumerable allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static) - .Where(FilterMembers); + .Where(m => m is PropertyInfo p ? !ReflectionUtils.IsIndexedProperty(p) : true); List serializableMembers = new List(); if (memberSerialization != MemberSerialization.Fields) { #if HAVE_DATA_CONTRACTS - DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType); + DataContractAttribute? dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType); #endif #pragma warning disable 618 + // Exclude index properties and ByRef types List defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags) .Where(FilterMembers).ToList(); #pragma warning restore 618 @@ -349,9 +352,9 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(contract.NonNullableUnderlyingType, ignoreSerializableAttribute); contract.Properties.AddRange(CreateProperties(contract.NonNullableUnderlyingType, contract.MemberSerialization)); - Func extensionDataNameResolver = null; + Func? extensionDataNameResolver = null; - JsonObjectAttribute attribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); + JsonObjectAttribute? attribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); if (attribute != null) { contract.ItemRequired = attribute._itemRequired; @@ -360,7 +363,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) if (attribute.NamingStrategyType != null) { - NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(attribute); + NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(attribute)!; extensionDataNameResolver = s => namingStrategy.GetDictionaryKey(s); } } @@ -374,7 +377,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) if (contract.IsInstantiable) { - ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); // check if a JsonConstructorAttribute has been defined and use that if (overrideConstructor != null) @@ -395,7 +398,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) } else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic) { - ConstructorInfo constructor = GetParameterizedConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? constructor = GetParameterizedConstructor(contract.NonNullableUnderlyingType); if (constructor != null) { contract.ParameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructor); @@ -406,7 +409,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) { // value types always have default constructor // check whether there is a constructor that matches with non-writable properties on value type - ConstructorInfo constructor = GetImmutableConstructor(contract.NonNullableUnderlyingType, contract.Properties); + ConstructorInfo? constructor = GetImmutableConstructor(contract.NonNullableUnderlyingType, contract.Properties); if (constructor != null) { contract.OverrideCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructor); @@ -415,7 +418,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType) } } - MemberInfo extensionDataMember = GetExtensionDataMemberForType(contract.NonNullableUnderlyingType); + MemberInfo? extensionDataMember = GetExtensionDataMemberForType(contract.NonNullableUnderlyingType); if (extensionDataMember != null) { SetExtensionDataDelegates(contract, extensionDataMember); @@ -436,7 +439,7 @@ private static void ThrowUnableToSerializeError(object o, StreamingContext conte throw new JsonSerializationException("Unable to serialize instance of '{0}'.".FormatWith(CultureInfo.InvariantCulture, o.GetType())); } - private MemberInfo GetExtensionDataMemberForType(Type type) + private MemberInfo? GetExtensionDataMemberForType(Type type) { IEnumerable members = GetClassHierarchyForType(type).SelectMany(baseType => { @@ -447,7 +450,7 @@ private MemberInfo GetExtensionDataMemberForType(Type type) return m; }); - MemberInfo extensionDataMember = members.LastOrDefault(m => + MemberInfo? extensionDataMember = members.LastOrDefault(m => { MemberTypes memberType = m.MemberType(); if (memberType != MemberTypes.Property && memberType != MemberTypes.Field) @@ -463,12 +466,12 @@ private MemberInfo GetExtensionDataMemberForType(Type type) if (!ReflectionUtils.CanReadMemberValue(m, true)) { - throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' must have a getter.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType), m.Name)); + throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' must have a getter.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType!), m.Name)); } Type t = ReflectionUtils.GetMemberUnderlyingType(m); - if (ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type dictionaryType)) + if (ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type? dictionaryType)) { Type keyType = dictionaryType.GetGenericArguments()[0]; Type valueType = dictionaryType.GetGenericArguments()[1]; @@ -479,7 +482,7 @@ private MemberInfo GetExtensionDataMemberForType(Type type) } } - throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType), m.Name)); + throw new JsonException("Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType!), m.Name)); }); return extensionDataMember; @@ -487,7 +490,7 @@ private MemberInfo GetExtensionDataMemberForType(Type type) private static void SetExtensionDataDelegates(JsonObjectContract contract, MemberInfo member) { - JsonExtensionDataAttribute extensionDataAttribute = ReflectionUtils.GetAttribute(member); + JsonExtensionDataAttribute? extensionDataAttribute = ReflectionUtils.GetAttribute(member); if (extensionDataAttribute == null) { return; @@ -495,10 +498,10 @@ private static void SetExtensionDataDelegates(JsonObjectContract contract, Membe Type t = ReflectionUtils.GetMemberUnderlyingType(member); - ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type dictionaryType); + ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type? dictionaryType); - Type keyType = dictionaryType.GetGenericArguments()[0]; - Type valueType = dictionaryType.GetGenericArguments()[1]; + Type keyType = dictionaryType!.GetGenericArguments()[0]; + Type valueType = dictionaryType!.GetGenericArguments()[1]; Type createdType; @@ -512,27 +515,27 @@ private static void SetExtensionDataDelegates(JsonObjectContract contract, Membe createdType = t; } - Func getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(member); + Func getExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(member); if (extensionDataAttribute.ReadData) { - Action setExtensionDataDictionary = (ReflectionUtils.CanSetMemberValue(member, true, false)) + Action? setExtensionDataDictionary = (ReflectionUtils.CanSetMemberValue(member, true, false)) ? JsonTypeReflector.ReflectionDelegateFactory.CreateSet(member) : null; Func createExtensionDataDictionary = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor(createdType); - MethodInfo setMethod = t.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); + MethodInfo? setMethod = t.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); if (setMethod == null) { // Item is explicitly implemented and non-public // get from dictionary interface - setMethod = dictionaryType.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); + setMethod = dictionaryType!.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance, null, valueType, new[] { keyType }, null)?.GetSetMethod(); } - MethodCall setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMethod); + MethodCall setExtensionDataDictionaryValue = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMethod!); ExtensionDataSetter extensionDataSetter = (o, key, value) => { - object dictionary = getExtensionDataDictionary(o); + object? dictionary = getExtensionDataDictionary(o); if (dictionary == null) { if (setExtensionDataDictionary == null) @@ -558,7 +561,7 @@ private static void SetExtensionDataDelegates(JsonObjectContract contract, Membe ExtensionDataGetter extensionDataGetter = o => { - object dictionary = getExtensionDataDictionary(o); + object? dictionary = getExtensionDataDictionary(o); if (dictionary == null) { return null; @@ -589,7 +592,7 @@ public IEnumerator> GetEnumerator() { foreach (KeyValuePair item in _e) { - yield return new KeyValuePair(item.Key, item.Value); + yield return new KeyValuePair(item.Key!, item.Value!); } } @@ -599,7 +602,7 @@ IEnumerator IEnumerable.GetEnumerator() } } - private ConstructorInfo GetAttributeConstructor(Type objectType) + private ConstructorInfo? GetAttributeConstructor(Type objectType) { IEnumerator en = objectType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(c => c.IsDefined(typeof(JsonConstructorAttribute), true)).GetEnumerator(); @@ -623,7 +626,7 @@ private ConstructorInfo GetAttributeConstructor(Type objectType) return null; } - private ConstructorInfo GetImmutableConstructor(Type objectType, JsonPropertyCollection memberProperties) + private ConstructorInfo? GetImmutableConstructor(Type objectType, JsonPropertyCollection memberProperties) { IEnumerable constructors = objectType.GetConstructors(); IEnumerator en = constructors.GetEnumerator(); @@ -637,7 +640,7 @@ private ConstructorInfo GetImmutableConstructor(Type objectType, JsonPropertyCol { foreach (ParameterInfo parameterInfo in parameters) { - JsonProperty memberProperty = MatchProperty(memberProperties, parameterInfo.Name, parameterInfo.ParameterType); + JsonProperty? memberProperty = MatchProperty(memberProperties, parameterInfo.Name!, parameterInfo.ParameterType); if (memberProperty == null || memberProperty.Writable) { return null; @@ -652,7 +655,7 @@ private ConstructorInfo GetImmutableConstructor(Type objectType, JsonPropertyCol return null; } - private ConstructorInfo GetParameterizedConstructor(Type objectType) + private ConstructorInfo? GetParameterizedConstructor(Type objectType) { #if PORTABLE IEnumerable constructors = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance); @@ -685,11 +688,16 @@ protected virtual IList CreateConstructorParameters(ConstructorInf { ParameterInfo[] constructorParameters = constructor.GetParameters(); - JsonPropertyCollection parameterCollection = new JsonPropertyCollection(constructor.DeclaringType); + JsonPropertyCollection parameterCollection = new JsonPropertyCollection(constructor.DeclaringType!); foreach (ParameterInfo parameterInfo in constructorParameters) { - JsonProperty matchingMemberProperty = MatchProperty(memberProperties, parameterInfo.Name, parameterInfo.ParameterType); + if (parameterInfo.Name == null) + { + continue; + } + + JsonProperty? matchingMemberProperty = MatchProperty(memberProperties, parameterInfo.Name, parameterInfo.ParameterType); // ensure that property will have a name from matching property or from parameterinfo // parameterinfo could have no name if generated by a proxy (I'm looking at you Castle) @@ -707,7 +715,7 @@ protected virtual IList CreateConstructorParameters(ConstructorInf return parameterCollection; } - private JsonProperty MatchProperty(JsonPropertyCollection properties, string name, Type type) + private JsonProperty? MatchProperty(JsonPropertyCollection properties, string name, Type type) { // it is possible to generate a member with a null name using Reflection.Emit // protect against an ArgumentNullException from GetClosestMatchProperty by testing for null here @@ -716,7 +724,7 @@ private JsonProperty MatchProperty(JsonPropertyCollection properties, string nam return null; } - JsonProperty property = properties.GetClosestMatchProperty(name); + JsonProperty? property = properties.GetClosestMatchProperty(name); // must match type as well as name if (property == null || property.PropertyType != type) { @@ -732,13 +740,13 @@ private JsonProperty MatchProperty(JsonPropertyCollection properties, string nam /// The matching member property. /// The constructor parameter. /// A created for the given . - protected virtual JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo) + protected virtual JsonProperty CreatePropertyFromConstructorParameter(JsonProperty? matchingMemberProperty, ParameterInfo parameterInfo) { JsonProperty property = new JsonProperty(); property.PropertyType = parameterInfo.ParameterType; property.AttributeProvider = new ReflectionAttributeProvider(parameterInfo); - SetPropertySettingsFromAttributes(property, parameterInfo, parameterInfo.Name, parameterInfo.Member.DeclaringType, MemberSerialization.OptOut, out _); + SetPropertySettingsFromAttributes(property, parameterInfo, parameterInfo.Name!, parameterInfo.Member.DeclaringType!, MemberSerialization.OptOut, out _); property.Readable = false; property.Writable = true; @@ -771,7 +779,7 @@ protected virtual JsonProperty CreatePropertyFromConstructorParameter(JsonProper /// /// Type of the object. /// The contract's default . - protected virtual JsonConverter ResolveContractConverter(Type objectType) + protected virtual JsonConverter? ResolveContractConverter(Type objectType) { return JsonTypeReflector.GetJsonConverter(objectType); } @@ -786,7 +794,7 @@ private Func GetDefaultCreator(Type createdType) #endif private void InitializeContract(JsonContract contract) { - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetCachedAttribute(contract.NonNullableUnderlyingType); if (containerAttribute != null) { contract.IsReference = containerAttribute._isReference; @@ -794,7 +802,7 @@ private void InitializeContract(JsonContract contract) #if HAVE_DATA_CONTRACTS else { - DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(contract.NonNullableUnderlyingType); + DataContractAttribute? dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(contract.NonNullableUnderlyingType); // doesn't have a null value if (dataContractAttribute != null && dataContractAttribute.IsReference) { @@ -824,11 +832,11 @@ private void ResolveCallbackMethods(JsonContract contract, Type t) { GetCallbackMethodsForType( t, - out List onSerializing, - out List onSerialized, - out List onDeserializing, - out List onDeserialized, - out List onError); + out List? onSerializing, + out List? onSerialized, + out List? onDeserializing, + out List? onDeserialized, + out List? onError); if (onSerializing != null) { @@ -856,7 +864,7 @@ private void ResolveCallbackMethods(JsonContract contract, Type t) } } - private void GetCallbackMethodsForType(Type type, out List onSerializing, out List onSerialized, out List onDeserializing, out List onDeserialized, out List onError) + private void GetCallbackMethodsForType(Type type, out List? onSerializing, out List? onSerialized, out List? onDeserializing, out List? onDeserialized, out List? onError) { onSerializing = null; onSerialized = null; @@ -867,11 +875,11 @@ private void GetCallbackMethodsForType(Type type, out List GetClassHierarchyForType(Type type) { List ret = new List(); - Type current = type; + Type? current = type; while (current != null && current != typeof(object)) { ret.Add(current); @@ -1003,10 +1011,10 @@ protected virtual JsonDictionaryContract CreateDictionaryContract(Type objectTyp JsonDictionaryContract contract = new JsonDictionaryContract(objectType); InitializeContract(contract); - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(objectType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute(objectType); if (containerAttribute?.NamingStrategyType != null) { - NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute); + NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute)!; contract.DictionaryKeyResolver = s => namingStrategy.GetDictionaryKey(s); } else @@ -1014,7 +1022,7 @@ protected virtual JsonDictionaryContract CreateDictionaryContract(Type objectTyp contract.DictionaryKeyResolver = ResolveDictionaryKey; } - ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); if (overrideConstructor != null) { @@ -1052,7 +1060,7 @@ protected virtual JsonArrayContract CreateArrayContract(Type objectType) JsonArrayContract contract = new JsonArrayContract(objectType); InitializeContract(contract); - ConstructorInfo overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); + ConstructorInfo? overrideConstructor = GetAttributeConstructor(contract.NonNullableUnderlyingType); if (overrideConstructor != null) { @@ -1119,7 +1127,7 @@ protected virtual JsonISerializableContract CreateISerializableContract(Type obj if (contract.IsInstantiable) { - ConstructorInfo constructorInfo = contract.NonNullableUnderlyingType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] {typeof(SerializationInfo), typeof(StreamingContext)}, null); + ConstructorInfo? constructorInfo = contract.NonNullableUnderlyingType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] {typeof(SerializationInfo), typeof(StreamingContext)}, null); if (constructorInfo != null) { ObjectConstructor creator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(constructorInfo); @@ -1143,10 +1151,10 @@ protected virtual JsonDynamicContract CreateDynamicContract(Type objectType) JsonDynamicContract contract = new JsonDynamicContract(objectType); InitializeContract(contract); - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(objectType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute(objectType); if (containerAttribute?.NamingStrategyType != null) { - NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute); + NamingStrategy namingStrategy = JsonTypeReflector.GetContainerNamingStrategy(containerAttribute)!; contract.PropertyNameResolver = s => namingStrategy.GetDictionaryKey(s); } else @@ -1188,7 +1196,7 @@ protected virtual JsonContract CreateContract(Type objectType) } t = ReflectionUtils.EnsureNotNullableType(t); - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetCachedAttribute(t); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetCachedAttribute(t); if (containerAttribute is JsonObjectAttribute) { @@ -1284,10 +1292,17 @@ internal static bool CanConvertToString(Type type) return true; } +#if HAVE_DATE_ONLY + if (type == typeof(DateOnly) || type == typeof(TimeOnly)) + { + return true; + } +#endif + return false; } - private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType) + private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo? currentCallback, ref Type? prevAttributeType) { if (!method.IsDefined(attributeType, false)) { @@ -1296,36 +1311,36 @@ private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameter if (currentCallback != null) { - throw new JsonException("Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'.".FormatWith(CultureInfo.InvariantCulture, method, currentCallback, GetClrTypeFullName(method.DeclaringType), attributeType)); + throw new JsonException("Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'.".FormatWith(CultureInfo.InvariantCulture, method, currentCallback, GetClrTypeFullName(method.DeclaringType!), attributeType)); } if (prevAttributeType != null) { - throw new JsonException("Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType), method)); + throw new JsonException("Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType!), method)); } if (method.IsVirtual) { - throw new JsonException("Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType), attributeType)); + throw new JsonException("Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType!), attributeType)); } if (method.ReturnType != typeof(void)) { - throw new JsonException("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method)); + throw new JsonException("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method)); } if (attributeType == typeof(OnErrorAttribute)) { if (parameters == null || parameters.Length != 2 || parameters[0].ParameterType != typeof(StreamingContext) || parameters[1].ParameterType != typeof(ErrorContext)) { - throw new JsonException("Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext), typeof(ErrorContext))); + throw new JsonException("Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method, typeof(StreamingContext), typeof(ErrorContext))); } } else { if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext)) { - throw new JsonException("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext))); + throw new JsonException("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method, typeof(StreamingContext))); } } @@ -1338,7 +1353,7 @@ internal static string GetClrTypeFullName(Type type) { if (type.IsGenericTypeDefinition() || !type.ContainsGenericParameters()) { - return type.FullName; + return type.FullName!; } return "{0}.{1}".FormatWith(CultureInfo.InvariantCulture, type.Namespace, type.Name); @@ -1371,7 +1386,7 @@ protected virtual IList CreateProperties(Type type, MemberSerializ // nametable is not thread-safe for multiple writers lock (nameTable) { - property.PropertyName = nameTable.Add(property.PropertyName); + property.PropertyName = nameTable.Add(property.PropertyName!); } properties.AddProperty(property); @@ -1397,7 +1412,7 @@ protected virtual IValueProvider CreateMemberValueProvider(MemberInfo member) // warning - this method use to cause errors with Intellitrace. Retest in VS Ultimate after changes IValueProvider valueProvider; -#if !(PORTABLE40 || PORTABLE || DOTNET || NETSTANDARD2_0) +#if !(PORTABLE40 || PORTABLE || DOTNET || NETSTANDARD2_0 || NET6_0_OR_GREATER) if (DynamicCodeGeneration) { valueProvider = new DynamicValueProvider(member); @@ -1429,7 +1444,7 @@ protected virtual JsonProperty CreateProperty(MemberInfo member, MemberSerializa property.ValueProvider = CreateMemberValueProvider(member); property.AttributeProvider = new ReflectionAttributeProvider(member); - SetPropertySettingsFromAttributes(property, member, member.Name, member.DeclaringType, memberSerialization, out bool allowNonPublicAccess); + SetPropertySettingsFromAttributes(property, member, member.Name, member.DeclaringType!, memberSerialization, out bool allowNonPublicAccess); if (memberSerialization != MemberSerialization.Fields) { @@ -1459,11 +1474,11 @@ protected virtual JsonProperty CreateProperty(MemberInfo member, MemberSerializa private void SetPropertySettingsFromAttributes(JsonProperty property, object attributeProvider, string name, Type declaringType, MemberSerialization memberSerialization, out bool allowNonPublicAccess) { #if HAVE_DATA_CONTRACTS - DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(declaringType); + DataContractAttribute? dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(declaringType); - MemberInfo memberInfo = attributeProvider as MemberInfo; + MemberInfo? memberInfo = attributeProvider as MemberInfo; - DataMemberAttribute dataMemberAttribute; + DataMemberAttribute? dataMemberAttribute; if (dataContractAttribute != null && memberInfo != null) { dataMemberAttribute = JsonTypeReflector.GetDataMemberAttribute((MemberInfo)memberInfo); @@ -1474,8 +1489,8 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att } #endif - JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute(attributeProvider); - JsonRequiredAttribute requiredAttribute = JsonTypeReflector.GetAttribute(attributeProvider); + JsonPropertyAttribute? propertyAttribute = JsonTypeReflector.GetAttribute(attributeProvider); + JsonRequiredAttribute? requiredAttribute = JsonTypeReflector.GetAttribute(attributeProvider); string mappedName; bool hasSpecifiedName; @@ -1497,9 +1512,9 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att hasSpecifiedName = false; } - JsonContainerAttribute containerAttribute = JsonTypeReflector.GetAttribute(declaringType); + JsonContainerAttribute? containerAttribute = JsonTypeReflector.GetAttribute(declaringType); - NamingStrategy namingStrategy; + NamingStrategy? namingStrategy; if (propertyAttribute?.NamingStrategyType != null) { namingStrategy = JsonTypeReflector.CreateNamingStrategyInstance(propertyAttribute.NamingStrategyType, propertyAttribute.NamingStrategyParameters); @@ -1602,7 +1617,7 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att // the class type might have a converter but the property converter takes precedence property.Converter = JsonTypeReflector.GetJsonConverter(attributeProvider); - DefaultValueAttribute defaultValueAttribute = JsonTypeReflector.GetAttribute(attributeProvider); + DefaultValueAttribute? defaultValueAttribute = JsonTypeReflector.GetAttribute(attributeProvider); if (defaultValueAttribute != null) { property.DefaultValue = defaultValueAttribute.Value; @@ -1625,24 +1640,24 @@ private void SetPropertySettingsFromAttributes(JsonProperty property, object att } } - private Predicate CreateShouldSerializeTest(MemberInfo member) + private Predicate? CreateShouldSerializeTest(MemberInfo member) { - MethodInfo shouldSerializeMethod = member.DeclaringType.GetMethod(JsonTypeReflector.ShouldSerializePrefix + member.Name, ReflectionUtils.EmptyTypes); + MethodInfo? shouldSerializeMethod = member.DeclaringType!.GetMethod(JsonTypeReflector.ShouldSerializePrefix + member.Name, ReflectionUtils.EmptyTypes); if (shouldSerializeMethod == null || shouldSerializeMethod.ReturnType != typeof(bool)) { return null; } - MethodCall shouldSerializeCall = + MethodCall shouldSerializeCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(shouldSerializeMethod); - return o => (bool)shouldSerializeCall(o); + return o => (bool)shouldSerializeCall(o)!; } private void SetIsSpecifiedActions(JsonProperty property, MemberInfo member, bool allowNonPublicAccess) { - MemberInfo specifiedMember = member.DeclaringType.GetProperty(member.Name + JsonTypeReflector.SpecifiedPostfix, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + MemberInfo? specifiedMember = member.DeclaringType!.GetProperty(member.Name + JsonTypeReflector.SpecifiedPostfix, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (specifiedMember == null) { specifiedMember = member.DeclaringType.GetField(member.Name + JsonTypeReflector.SpecifiedPostfix, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); @@ -1653,7 +1668,7 @@ private void SetIsSpecifiedActions(JsonProperty property, MemberInfo member, boo return; } - Func specifiedPropertyGet = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(specifiedMember); + Func specifiedPropertyGet = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(specifiedMember)!; property.GetIsSpecified = o => (bool)specifiedPropertyGet(o); diff --git a/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs b/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs index 83e0f4846..e33dc58b1 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs @@ -52,15 +52,15 @@ private BidirectionalDictionary GetMappings(object context) public object ResolveReference(object context, string reference) { - GetMappings(context).TryGetByFirst(reference, out object value); - return value; + GetMappings(context).TryGetByFirst(reference, out object? value); + return value!; } public string GetReference(object context, object value) { BidirectionalDictionary mappings = GetMappings(context); - if (!mappings.TryGetBySecond(value, out string reference)) + if (!mappings.TryGetBySecond(value, out string? reference)) { _referenceCount++; reference = _referenceCount.ToString(CultureInfo.InvariantCulture); diff --git a/Src/Newtonsoft.Json/Serialization/DefaultSerializationBinder.cs b/Src/Newtonsoft.Json/Serialization/DefaultSerializationBinder.cs index 90af80338..37d25cf26 100644 --- a/Src/Newtonsoft.Json/Serialization/DefaultSerializationBinder.cs +++ b/Src/Newtonsoft.Json/Serialization/DefaultSerializationBinder.cs @@ -43,24 +43,24 @@ public class DefaultSerializationBinder : { internal static readonly DefaultSerializationBinder Instance = new DefaultSerializationBinder(); - private readonly ThreadSafeStore, Type> _typeCache; + private readonly ThreadSafeStore, Type> _typeCache; /// /// Initializes a new instance of the class. /// public DefaultSerializationBinder() { - _typeCache = new ThreadSafeStore, Type>(GetTypeFromTypeNameKey); + _typeCache = new ThreadSafeStore, Type>(GetTypeFromTypeNameKey); } - private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) + private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) { - string assemblyName = typeNameKey.Value1; + string? assemblyName = typeNameKey.Value1; string typeName = typeNameKey.Value2; if (assemblyName != null) { - Assembly assembly; + Assembly? assembly; #if !(DOTNET || PORTABLE40 || PORTABLE) // look, I don't like using obsolete methods as much as you do but this is the only way @@ -96,12 +96,12 @@ private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) throw new JsonSerializationException("Could not load assembly '{0}'.".FormatWith(CultureInfo.InvariantCulture, assemblyName)); } - Type type = assembly.GetType(typeName); + Type? type = assembly.GetType(typeName); if (type == null) { // if generic type, try manually parsing the type arguments for the case of dynamically loaded assemblies // example generic typeName format: System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] - if (typeName.IndexOf('`') >= 0) + if (StringUtils.IndexOf(typeName, '`') >= 0) { try { @@ -123,18 +123,18 @@ private Type GetTypeFromTypeNameKey(StructMultiKey typeNameKey) } else { - return Type.GetType(typeName); + return Type.GetType(typeName)!; } } - private Type GetGenericTypeFromTypeName(string typeName, Assembly assembly) + private Type? GetGenericTypeFromTypeName(string typeName, Assembly assembly) { - Type type = null; - int openBracketIndex = typeName.IndexOf('['); + Type? type = null; + int openBracketIndex = StringUtils.IndexOf(typeName, '['); if (openBracketIndex >= 0) { string genericTypeDefName = typeName.Substring(0, openBracketIndex); - Type genericTypeDef = assembly.GetType(genericTypeDefName); + Type? genericTypeDef = assembly.GetType(genericTypeDefName); if (genericTypeDef != null) { List genericTypeArguments = new List(); @@ -159,7 +159,7 @@ private Type GetGenericTypeFromTypeName(string typeName, Assembly assembly) { string typeArgAssemblyQualifiedName = typeName.Substring(typeArgStartIndex, i - typeArgStartIndex); - StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(typeArgAssemblyQualifiedName); + StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(typeArgAssemblyQualifiedName); genericTypeArguments.Add(GetTypeByName(typeNameKey)); } break; @@ -173,7 +173,7 @@ private Type GetGenericTypeFromTypeName(string typeName, Assembly assembly) return type; } - private Type GetTypeByName(StructMultiKey typeNameKey) + private Type GetTypeByName(StructMultiKey typeNameKey) { return _typeCache.Get(typeNameKey); } @@ -186,9 +186,9 @@ private Type GetTypeByName(StructMultiKey typeNameKey) /// /// The type of the object the formatter creates a new instance of. /// - public override Type BindToType(string assemblyName, string typeName) + public override Type BindToType(string? assemblyName, string typeName) { - return GetTypeByName(new StructMultiKey(assemblyName, typeName)); + return GetTypeByName(new StructMultiKey(assemblyName, typeName)); } /// @@ -201,7 +201,7 @@ public override Type BindToType(string assemblyName, string typeName) #if HAVE_SERIALIZATION_BINDER_BIND_TO_NAME override #endif - void BindToName(Type serializedType, out string assemblyName, out string typeName) + void BindToName(Type serializedType, out string? assemblyName, out string? typeName) { #if !HAVE_FULL_REFLECTION assemblyName = serializedType.GetTypeInfo().Assembly.FullName; diff --git a/Src/Newtonsoft.Json/Serialization/DiagnosticsTraceWriter.cs b/Src/Newtonsoft.Json/Serialization/DiagnosticsTraceWriter.cs index 0f8b8fbf5..23ece092c 100644 --- a/Src/Newtonsoft.Json/Serialization/DiagnosticsTraceWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/DiagnosticsTraceWriter.cs @@ -43,7 +43,7 @@ private TraceEventType GetTraceEventType(TraceLevel level) /// The at which to write this trace. /// The trace message. /// The trace exception. This parameter is optional. - public void Trace(TraceLevel level, string message, Exception ex) + public void Trace(TraceLevel level, string message, Exception? ex) { if (level == TraceLevel.Off) { diff --git a/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs b/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs index ec9231c7b..cb19a61e0 100644 --- a/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs +++ b/Src/Newtonsoft.Json/Serialization/DynamicValueProvider.cs @@ -42,8 +42,8 @@ namespace Newtonsoft.Json.Serialization public class DynamicValueProvider : IValueProvider { private readonly MemberInfo _memberInfo; - private Func _getter; - private Action _setter; + private Func? _getter; + private Action? _setter; /// /// Initializes a new instance of the class. @@ -60,7 +60,7 @@ public DynamicValueProvider(MemberInfo memberInfo) /// /// The target to set the value on. /// The value to set on the target. - public void SetValue(object target, object value) + public void SetValue(object target, object? value) { try { @@ -98,7 +98,7 @@ public void SetValue(object target, object value) /// /// The target to get the value from. /// The value. - public object GetValue(object target) + public object? GetValue(object target) { try { diff --git a/Src/Newtonsoft.Json/Serialization/ErrorContext.cs b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs index 366064a0c..173fb7f75 100644 --- a/Src/Newtonsoft.Json/Serialization/ErrorContext.cs +++ b/Src/Newtonsoft.Json/Serialization/ErrorContext.cs @@ -32,7 +32,7 @@ namespace Newtonsoft.Json.Serialization /// public class ErrorContext { - internal ErrorContext(object originalObject, object member, string path, Exception error) + internal ErrorContext(object? originalObject, object? member, string path, Exception error) { OriginalObject = originalObject; Member = member; @@ -52,13 +52,13 @@ internal ErrorContext(object originalObject, object member, string path, Excepti /// Gets the original object that caused the error. /// /// The original object that caused the error. - public object OriginalObject { get; } + public object? OriginalObject { get; } /// /// Gets the member that caused the error. /// /// The member that caused the error. - public object Member { get; } + public object? Member { get; } /// /// Gets the path of the JSON location where the error occurred. diff --git a/Src/Newtonsoft.Json/Serialization/ErrorEventArgs.cs b/Src/Newtonsoft.Json/Serialization/ErrorEventArgs.cs index 1b16c6072..8231abbb4 100644 --- a/Src/Newtonsoft.Json/Serialization/ErrorEventArgs.cs +++ b/Src/Newtonsoft.Json/Serialization/ErrorEventArgs.cs @@ -36,7 +36,7 @@ public class ErrorEventArgs : EventArgs /// Gets the current object the error event is being raised against. /// /// The current object the error event is being raised against. - public object CurrentObject { get; } + public object? CurrentObject { get; } /// /// Gets the error context. @@ -49,7 +49,7 @@ public class ErrorEventArgs : EventArgs /// /// The current object. /// The error context. - public ErrorEventArgs(object currentObject, ErrorContext errorContext) + public ErrorEventArgs(object? currentObject, ErrorContext errorContext) { CurrentObject = currentObject; ErrorContext = errorContext; diff --git a/Src/Newtonsoft.Json/Serialization/ExpressionValueProvider.cs b/Src/Newtonsoft.Json/Serialization/ExpressionValueProvider.cs index ae2a3086f..99da718de 100644 --- a/Src/Newtonsoft.Json/Serialization/ExpressionValueProvider.cs +++ b/Src/Newtonsoft.Json/Serialization/ExpressionValueProvider.cs @@ -43,8 +43,8 @@ namespace Newtonsoft.Json.Serialization public class ExpressionValueProvider : IValueProvider { private readonly MemberInfo _memberInfo; - private Func _getter; - private Action _setter; + private Func? _getter; + private Action? _setter; /// /// Initializes a new instance of the class. @@ -61,7 +61,7 @@ public ExpressionValueProvider(MemberInfo memberInfo) /// /// The target to set the value on. /// The value to set on the target. - public void SetValue(object target, object value) + public void SetValue(object target, object? value) { try { @@ -99,7 +99,7 @@ public void SetValue(object target, object value) /// /// The target to get the value from. /// The value. - public object GetValue(object target) + public object? GetValue(object target) { try { diff --git a/Src/Newtonsoft.Json/Serialization/ISerializationBinder.cs b/Src/Newtonsoft.Json/Serialization/ISerializationBinder.cs index bf70891b7..64ce1c3fc 100644 --- a/Src/Newtonsoft.Json/Serialization/ISerializationBinder.cs +++ b/Src/Newtonsoft.Json/Serialization/ISerializationBinder.cs @@ -40,7 +40,7 @@ public interface ISerializationBinder /// Specifies the name of the serialized object. /// Specifies the name of the serialized object /// The type of the object the formatter creates a new instance of. - Type BindToType(string assemblyName, string typeName); + Type BindToType(string? assemblyName, string typeName); /// /// When implemented, controls the binding of a serialized object to a type. @@ -48,6 +48,6 @@ public interface ISerializationBinder /// The type of the object the formatter creates a new instance of. /// Specifies the name of the serialized object. /// Specifies the name of the serialized object. - void BindToName(Type serializedType, out string assemblyName, out string typeName); + void BindToName(Type serializedType, out string? assemblyName, out string? typeName); } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/ITraceWriter.cs b/Src/Newtonsoft.Json/Serialization/ITraceWriter.cs index ac0b166ed..57f24721c 100644 --- a/Src/Newtonsoft.Json/Serialization/ITraceWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/ITraceWriter.cs @@ -23,6 +23,6 @@ public interface ITraceWriter /// The at which to write this trace. /// The trace message. /// The trace exception. This parameter is optional. - void Trace(TraceLevel level, string message, Exception ex); + void Trace(TraceLevel level, string message, Exception? ex); } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/IValueProvider.cs b/Src/Newtonsoft.Json/Serialization/IValueProvider.cs index 921724f81..7bfd610a6 100644 --- a/Src/Newtonsoft.Json/Serialization/IValueProvider.cs +++ b/Src/Newtonsoft.Json/Serialization/IValueProvider.cs @@ -35,13 +35,13 @@ public interface IValueProvider /// /// The target to set the value on. /// The value to set on the target. - void SetValue(object target, object value); + void SetValue(object target, object? value); /// /// Gets the value. /// /// The target to get the value from. /// The value. - object GetValue(object target); + object? GetValue(object target); } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs index d7f4106f4..87c409e6d 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonArrayContract.cs @@ -31,6 +31,7 @@ using System.Reflection; using Newtonsoft.Json.Utilities; using System.Collections; +using System.Diagnostics; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -49,7 +50,7 @@ public class JsonArrayContract : JsonContainerContract /// Gets the of the collection items. /// /// The of the collection items. - public Type CollectionItemType { get; } + public Type? CollectionItemType { get; } /// /// Gets a value indicating whether the collection type is a multidimensional array. @@ -57,26 +58,26 @@ public class JsonArrayContract : JsonContainerContract /// true if the collection type is a multidimensional array; otherwise, false. public bool IsMultidimensionalArray { get; } - private readonly Type _genericCollectionDefinitionType; + private readonly Type? _genericCollectionDefinitionType; - private Type _genericWrapperType; - private ObjectConstructor _genericWrapperCreator; - private Func _genericTemporaryCollectionCreator; + private Type? _genericWrapperType; + private ObjectConstructor? _genericWrapperCreator; + private Func? _genericTemporaryCollectionCreator; internal bool IsArray { get; } internal bool ShouldCreateWrapper { get; } internal bool CanDeserialize { get; private set; } - private readonly ConstructorInfo _parameterizedConstructor; + private readonly ConstructorInfo? _parameterizedConstructor; - private ObjectConstructor _parameterizedCreator; - private ObjectConstructor _overrideCreator; + private ObjectConstructor? _parameterizedCreator; + private ObjectConstructor? _overrideCreator; - internal ObjectConstructor ParameterizedCreator + internal ObjectConstructor? ParameterizedCreator { get { - if (_parameterizedCreator == null) + if (_parameterizedCreator == null && _parameterizedConstructor != null) { _parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor); } @@ -89,7 +90,7 @@ internal ObjectConstructor ParameterizedCreator /// Gets or sets the function used to create the object. When set this function will override . /// /// The function used to create the object. - public ObjectConstructor OverrideCreator + public ObjectConstructor? OverrideCreator { get => _overrideCreator; set @@ -116,19 +117,22 @@ public JsonArrayContract(Type underlyingType) : base(underlyingType) { ContractType = JsonContractType.Array; - IsArray = CreatedType.IsArray; + + // netcoreapp3.0 uses EmptyPartition for empty enumerable. Treat as an empty array. + IsArray = CreatedType.IsArray || + (NonNullableUnderlyingType.IsGenericType() && NonNullableUnderlyingType.GetGenericTypeDefinition().FullName == "System.Linq.EmptyPartition`1"); bool canDeserialize; - Type tempCollectionType; + Type? tempCollectionType; if (IsArray) { - CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType); + CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType)!; IsReadOnlyOrFixedSize = true; _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType); canDeserialize = true; - IsMultidimensionalArray = (IsArray && UnderlyingType.GetArrayRank() > 1); + IsMultidimensionalArray = (CreatedType.IsArray && UnderlyingType.GetArrayRank() > 1); } else if (typeof(IList).IsAssignableFrom(NonNullableUnderlyingType)) { @@ -251,11 +255,12 @@ public JsonArrayContract(Type underlyingType) } #endif - if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract( + if (CollectionItemType != null && + ImmutableCollectionsUtils.TryBuildImmutableForArrayContract( NonNullableUnderlyingType, CollectionItemType, - out Type immutableCreatedType, - out ObjectConstructor immutableParameterizedCreator)) + out Type? immutableCreatedType, + out ObjectConstructor? immutableParameterizedCreator)) { CreatedType = immutableCreatedType; _parameterizedCreator = immutableParameterizedCreator; @@ -268,6 +273,9 @@ internal IWrappedCollection CreateWrapper(object list) { if (_genericWrapperCreator == null) { + MiscellaneousUtils.Assert(_genericCollectionDefinitionType != null); + MiscellaneousUtils.Assert(CollectionItemType != null); + _genericWrapperType = typeof(CollectionWrapper<>).MakeGenericType(CollectionItemType); Type constructorArgument; @@ -282,7 +290,7 @@ internal IWrappedCollection CreateWrapper(object list) constructorArgument = _genericCollectionDefinitionType; } - ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { constructorArgument }); + ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { constructorArgument })!; _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(genericWrapperConstructor); } @@ -311,7 +319,7 @@ private void StoreFSharpListCreatorIfNecessary(Type underlyingType) if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpListTypeName) { FSharpUtils.EnsureInitialized(underlyingType.Assembly()); - _parameterizedCreator = FSharpUtils.CreateSeq(CollectionItemType); + _parameterizedCreator = FSharpUtils.Instance.CreateSeq(CollectionItemType!); } } #endif diff --git a/Src/Newtonsoft.Json/Serialization/JsonContainerContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContainerContract.cs index f1e7796b8..9956ed312 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonContainerContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonContainerContract.cs @@ -42,11 +42,11 @@ namespace Newtonsoft.Json.Serialization /// public class JsonContainerContract : JsonContract { - private JsonContract _itemContract; - private JsonContract _finalItemContract; + private JsonContract? _itemContract; + private JsonContract? _finalItemContract; // will be null for containers that don't have an item type (e.g. IList) or for complex objects - internal JsonContract ItemContract + internal JsonContract? ItemContract { get => _itemContract; set @@ -64,13 +64,13 @@ internal JsonContract ItemContract } // the final (i.e. can't be inherited from like a sealed class or valuetype) item contract - internal JsonContract FinalItemContract => _finalItemContract; + internal JsonContract? FinalItemContract => _finalItemContract; /// /// Gets or sets the default collection items . /// /// The converter. - public JsonConverter ItemConverter { get; set; } + public JsonConverter? ItemConverter { get; set; } /// /// Gets or sets a value indicating whether the collection items preserve object references. @@ -97,7 +97,7 @@ internal JsonContract ItemContract internal JsonContainerContract(Type underlyingType) : base(underlyingType) { - JsonContainerAttribute jsonContainerAttribute = JsonTypeReflector.GetCachedAttribute(underlyingType); + JsonContainerAttribute? jsonContainerAttribute = JsonTypeReflector.GetCachedAttribute(underlyingType); if (jsonContainerAttribute != null) { diff --git a/Src/Newtonsoft.Json/Serialization/JsonContract.cs b/Src/Newtonsoft.Json/Serialization/JsonContract.cs index 37365bb6d..d4f802cb9 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonContract.cs @@ -67,13 +67,13 @@ internal enum JsonContractType /// The object to set extension data on. /// The extension data key. /// The extension data value. - public delegate void ExtensionDataSetter(object o, string key, object value); + public delegate void ExtensionDataSetter(object o, string key, object? value); /// /// Gets extension data for an object during serialization. /// /// The object to set extension data on. - public delegate IEnumerable> ExtensionDataGetter(object o); + public delegate IEnumerable>? ExtensionDataGetter(object o); /// /// Contract details for a used by the . @@ -90,11 +90,11 @@ public abstract class JsonContract internal bool IsSealed; internal bool IsInstantiable; - private List _onDeserializedCallbacks; - private IList _onDeserializingCallbacks; - private IList _onSerializedCallbacks; - private IList _onSerializingCallbacks; - private IList _onErrorCallbacks; + private List? _onDeserializedCallbacks; + private List? _onDeserializingCallbacks; + private List? _onSerializedCallbacks; + private List? _onSerializingCallbacks; + private List? _onErrorCallbacks; private Type _createdType; /// @@ -112,6 +112,7 @@ public Type CreatedType get => _createdType; set { + ValidationUtils.ArgumentNotNull(value, nameof(value)); _createdType = value; IsSealed = _createdType.IsSealed(); @@ -129,14 +130,14 @@ public Type CreatedType /// Gets or sets the default for this contract. /// /// The converter. - public JsonConverter Converter { get; set; } + public JsonConverter? Converter { get; set; } /// /// Gets the internally resolved for the contract's type. /// This converter is used as a fallback converter when no other converter is resolved. /// Setting will always override this converter. /// - public JsonConverter InternalConverter { get; internal set; } + public JsonConverter? InternalConverter { get; internal set; } /// /// Gets or sets all methods called immediately after deserialization of the object. @@ -227,7 +228,7 @@ public IList OnErrorCallbacks /// Gets or sets the default creator method used to create the object. /// /// The default creator method used to create the object. - public Func DefaultCreator { get; set; } + public Func? DefaultCreator { get; set; } /// /// Gets or sets a value indicating whether the default creator is non-public. @@ -247,9 +248,9 @@ internal JsonContract(Type underlyingType) IsNullable = ReflectionUtils.IsNullable(underlyingType); - NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType) : underlyingType; + NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType)! : underlyingType; - CreatedType = NonNullableUnderlyingType; + _createdType = CreatedType = NonNullableUnderlyingType; IsConvertable = ConvertUtils.IsConvertible(NonNullableUnderlyingType); IsEnum = NonNullableUnderlyingType.IsEnum(); diff --git a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs index c486be2bd..25828d13b 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonDictionaryContract.cs @@ -45,41 +45,41 @@ public class JsonDictionaryContract : JsonContainerContract /// Gets or sets the dictionary key resolver. /// /// The dictionary key resolver. - public Func DictionaryKeyResolver { get; set; } + public Func? DictionaryKeyResolver { get; set; } /// /// Gets the of the dictionary keys. /// /// The of the dictionary keys. - public Type DictionaryKeyType { get; } + public Type? DictionaryKeyType { get; } /// /// Gets the of the dictionary values. /// /// The of the dictionary values. - public Type DictionaryValueType { get; } + public Type? DictionaryValueType { get; } - internal JsonContract KeyContract { get; set; } + internal JsonContract? KeyContract { get; set; } - private readonly Type _genericCollectionDefinitionType; + private readonly Type? _genericCollectionDefinitionType; - private Type _genericWrapperType; - private ObjectConstructor _genericWrapperCreator; + private Type? _genericWrapperType; + private ObjectConstructor? _genericWrapperCreator; - private Func _genericTemporaryDictionaryCreator; + private Func? _genericTemporaryDictionaryCreator; internal bool ShouldCreateWrapper { get; } - private readonly ConstructorInfo _parameterizedConstructor; + private readonly ConstructorInfo? _parameterizedConstructor; - private ObjectConstructor _overrideCreator; - private ObjectConstructor _parameterizedCreator; + private ObjectConstructor? _overrideCreator; + private ObjectConstructor? _parameterizedCreator; - internal ObjectConstructor ParameterizedCreator + internal ObjectConstructor? ParameterizedCreator { get { - if (_parameterizedCreator == null) + if (_parameterizedCreator == null && _parameterizedConstructor != null) { _parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor); } @@ -92,7 +92,7 @@ internal ObjectConstructor ParameterizedCreator /// Gets or sets the function used to create the object. When set this function will override . /// /// The function used to create the object. - public ObjectConstructor OverrideCreator + public ObjectConstructor? OverrideCreator { get => _overrideCreator; set => _overrideCreator = value; @@ -115,24 +115,24 @@ public JsonDictionaryContract(Type underlyingType) { ContractType = JsonContractType.Dictionary; - Type keyType; - Type valueType; + Type? keyType; + Type? valueType; - if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IDictionary<,>), out _genericCollectionDefinitionType)) + if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(IDictionary<,>), out _genericCollectionDefinitionType)) { keyType = _genericCollectionDefinitionType.GetGenericArguments()[0]; valueType = _genericCollectionDefinitionType.GetGenericArguments()[1]; - if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IDictionary<,>))) + if (ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(IDictionary<,>))) { CreatedType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); } - else if (underlyingType.IsGenericType()) + else if (NonNullableUnderlyingType.IsGenericType()) { // ConcurrentDictionary<,> + IDictionary setter + null value = error // wrap to use generic setter // https://github.com/JamesNK/Newtonsoft.Json/issues/1582 - Type typeDefinition = underlyingType.GetGenericTypeDefinition(); + Type typeDefinition = NonNullableUnderlyingType.GetGenericTypeDefinition(); if (typeDefinition.FullName == JsonTypeReflector.ConcurrentDictionaryTypeName) { ShouldCreateWrapper = true; @@ -140,17 +140,17 @@ public JsonDictionaryContract(Type underlyingType) } #if HAVE_READ_ONLY_COLLECTIONS - IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyDictionary<,>)); + IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(NonNullableUnderlyingType, typeof(ReadOnlyDictionary<,>)); #endif } #if HAVE_READ_ONLY_COLLECTIONS - else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IReadOnlyDictionary<,>), out _genericCollectionDefinitionType)) + else if (ReflectionUtils.ImplementsGenericDefinition(NonNullableUnderlyingType, typeof(IReadOnlyDictionary<,>), out _genericCollectionDefinitionType)) { keyType = _genericCollectionDefinitionType.GetGenericArguments()[0]; valueType = _genericCollectionDefinitionType.GetGenericArguments()[1]; - if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IReadOnlyDictionary<,>))) + if (ReflectionUtils.IsGenericDefinition(NonNullableUnderlyingType, typeof(IReadOnlyDictionary<,>))) { CreatedType = typeof(ReadOnlyDictionary<,>).MakeGenericType(keyType, valueType); } @@ -160,9 +160,9 @@ public JsonDictionaryContract(Type underlyingType) #endif else { - ReflectionUtils.GetDictionaryKeyValueTypes(UnderlyingType, out keyType, out valueType); + ReflectionUtils.GetDictionaryKeyValueTypes(NonNullableUnderlyingType, out keyType, out valueType); - if (UnderlyingType == typeof(IDictionary)) + if (NonNullableUnderlyingType == typeof(IDictionary)) { CreatedType = typeof(Dictionary); } @@ -176,10 +176,10 @@ public JsonDictionaryContract(Type underlyingType) typeof(IDictionary<,>).MakeGenericType(keyType, valueType)); #if HAVE_FSHARP_TYPES - if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpMapTypeName) + if (!HasParameterizedCreatorInternal && NonNullableUnderlyingType.Name == FSharpUtils.FSharpMapTypeName) { - FSharpUtils.EnsureInitialized(underlyingType.Assembly()); - _parameterizedCreator = FSharpUtils.CreateMap(keyType, valueType); + FSharpUtils.EnsureInitialized(NonNullableUnderlyingType.Assembly()); + _parameterizedCreator = FSharpUtils.Instance.CreateMap(keyType, valueType); } #endif } @@ -204,12 +204,14 @@ public JsonDictionaryContract(Type underlyingType) } #endif - if (ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract( - underlyingType, - DictionaryKeyType, - DictionaryValueType, - out Type immutableCreatedType, - out ObjectConstructor immutableParameterizedCreator)) + if (DictionaryKeyType != null && + DictionaryValueType != null && + ImmutableCollectionsUtils.TryBuildImmutableForDictionaryContract( + NonNullableUnderlyingType, + DictionaryKeyType, + DictionaryValueType, + out Type? immutableCreatedType, + out ObjectConstructor? immutableParameterizedCreator)) { CreatedType = immutableCreatedType; _parameterizedCreator = immutableParameterizedCreator; @@ -221,9 +223,9 @@ internal IWrappedDictionary CreateWrapper(object dictionary) { if (_genericWrapperCreator == null) { - _genericWrapperType = typeof(DictionaryWrapper<,>).MakeGenericType(DictionaryKeyType, DictionaryValueType); + _genericWrapperType = typeof(DictionaryWrapper<,>).MakeGenericType(DictionaryKeyType!, DictionaryValueType!); - ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType }); + ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType! })!; _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(genericWrapperConstructor); } diff --git a/Src/Newtonsoft.Json/Serialization/JsonDynamicContract.cs b/Src/Newtonsoft.Json/Serialization/JsonDynamicContract.cs index f8a6ad391..5908890ba 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonDynamicContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonDynamicContract.cs @@ -46,13 +46,13 @@ public class JsonDynamicContract : JsonContainerContract /// Gets or sets the property name resolver. /// /// The property name resolver. - public Func PropertyNameResolver { get; set; } + public Func? PropertyNameResolver { get; set; } private readonly ThreadSafeStore>> _callSiteGetters = new ThreadSafeStore>>(CreateCallSiteGetter); - private readonly ThreadSafeStore>> _callSiteSetters = - new ThreadSafeStore>>(CreateCallSiteSetter); + private readonly ThreadSafeStore>> _callSiteSetters = + new ThreadSafeStore>>(CreateCallSiteSetter); private static CallSite> CreateCallSiteGetter(string name) { @@ -61,11 +61,11 @@ private static CallSite> CreateCallSiteGetter(str return CallSite>.Create(new NoThrowGetBinderMember(getMemberBinder)); } - private static CallSite> CreateCallSiteSetter(string name) + private static CallSite> CreateCallSiteSetter(string name) { SetMemberBinder binder = (SetMemberBinder)DynamicUtils.BinderWrapper.SetMember(name, typeof(DynamicUtils)); - return CallSite>.Create(new NoThrowSetBinderMember(binder)); + return CallSite>.Create(new NoThrowSetBinderMember(binder)); } /// @@ -80,7 +80,7 @@ public JsonDynamicContract(Type underlyingType) Properties = new JsonPropertyCollection(UnderlyingType); } - internal bool TryGetMember(IDynamicMetaObjectProvider dynamicProvider, string name, out object value) + internal bool TryGetMember(IDynamicMetaObjectProvider dynamicProvider, string name, out object? value) { ValidationUtils.ArgumentNotNull(dynamicProvider, nameof(dynamicProvider)); @@ -100,11 +100,11 @@ internal bool TryGetMember(IDynamicMetaObjectProvider dynamicProvider, string na } } - internal bool TrySetMember(IDynamicMetaObjectProvider dynamicProvider, string name, object value) + internal bool TrySetMember(IDynamicMetaObjectProvider dynamicProvider, string name, object? value) { ValidationUtils.ArgumentNotNull(dynamicProvider, nameof(dynamicProvider)); - CallSite> callSite = _callSiteSetters.Get(name); + CallSite> callSite = _callSiteSetters.Get(name); object result = callSite.Target(callSite, dynamicProvider, value); diff --git a/Src/Newtonsoft.Json/Serialization/JsonFormatterConverter.cs b/Src/Newtonsoft.Json/Serialization/JsonFormatterConverter.cs index 52f61ae23..408a02975 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonFormatterConverter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonFormatterConverter.cs @@ -36,9 +36,9 @@ internal class JsonFormatterConverter : IFormatterConverter { private readonly JsonSerializerInternalReader _reader; private readonly JsonISerializableContract _contract; - private readonly JsonProperty _member; + private readonly JsonProperty? _member; - public JsonFormatterConverter(JsonSerializerInternalReader reader, JsonISerializableContract contract, JsonProperty member) + public JsonFormatterConverter(JsonSerializerInternalReader reader, JsonISerializableContract contract, JsonProperty? member) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); ValidationUtils.ArgumentNotNull(contract, nameof(contract)); @@ -53,7 +53,7 @@ private T GetTokenValue(object value) ValidationUtils.ArgumentNotNull(value, nameof(value)); JValue v = (JValue)value; - return (T)System.Convert.ChangeType(v.Value, typeof(T), CultureInfo.InvariantCulture); + return (T)System.Convert.ChangeType(v.Value, typeof(T), CultureInfo.InvariantCulture)!; } public object Convert(object value, Type type) @@ -65,19 +65,16 @@ public object Convert(object value, Type type) throw new ArgumentException("Value is not a JToken.", nameof(value)); } - return _reader.CreateISerializableItem(token, type, _contract, _member); + return _reader.CreateISerializableItem(token, type, _contract, _member)!; } public object Convert(object value, TypeCode typeCode) { ValidationUtils.ArgumentNotNull(value, nameof(value)); - if (value is JValue v) - { - value = v.Value; - } + object? resolvedValue = (value is JValue v) ? v.Value : value; - return System.Convert.ChangeType(value, typeCode, CultureInfo.InvariantCulture); + return System.Convert.ChangeType(resolvedValue, typeCode, CultureInfo.InvariantCulture)!; } public bool ToBoolean(object value) diff --git a/Src/Newtonsoft.Json/Serialization/JsonISerializableContract.cs b/Src/Newtonsoft.Json/Serialization/JsonISerializableContract.cs index f78181f45..55ea9e3a7 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonISerializableContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonISerializableContract.cs @@ -38,7 +38,7 @@ public class JsonISerializableContract : JsonContainerContract /// Gets or sets the object constructor. /// /// The object constructor. - public ObjectConstructor ISerializableCreator { get; set; } + public ObjectConstructor? ISerializableCreator { get; set; } /// /// Initializes a new instance of the class. diff --git a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs index 0a839a85d..221843dbd 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs @@ -91,13 +91,13 @@ public JsonPropertyCollection CreatorParameters /// This function is called with a collection of arguments which are defined by the collection. /// /// The function used to create the object. - public ObjectConstructor OverrideCreator + public ObjectConstructor? OverrideCreator { get => _overrideCreator; set => _overrideCreator = value; } - internal ObjectConstructor ParameterizedCreator + internal ObjectConstructor? ParameterizedCreator { get => _parameterizedCreator; set => _parameterizedCreator = value; @@ -106,17 +106,17 @@ internal ObjectConstructor ParameterizedCreator /// /// Gets or sets the extension data setter. /// - public ExtensionDataSetter ExtensionDataSetter { get; set; } + public ExtensionDataSetter? ExtensionDataSetter { get; set; } /// /// Gets or sets the extension data getter. /// - public ExtensionDataGetter ExtensionDataGetter { get; set; } + public ExtensionDataGetter? ExtensionDataGetter { get; set; } /// /// Gets or sets the extension data value type. /// - public Type ExtensionDataValueType + public Type? ExtensionDataValueType { get => _extensionDataValueType; set @@ -130,14 +130,14 @@ public Type ExtensionDataValueType /// Gets or sets the extension data name resolver. /// /// The extension data name resolver. - public Func ExtensionDataNameResolver { get; set; } + public Func? ExtensionDataNameResolver { get; set; } internal bool ExtensionDataIsJToken; private bool? _hasRequiredOrDefaultValueProperties; - private ObjectConstructor _overrideCreator; - private ObjectConstructor _parameterizedCreator; - private JsonPropertyCollection _creatorParameters; - private Type _extensionDataValueType; + private ObjectConstructor? _overrideCreator; + private ObjectConstructor? _parameterizedCreator; + private JsonPropertyCollection? _creatorParameters; + private Type? _extensionDataValueType; internal bool HasRequiredOrDefaultValueProperties { diff --git a/Src/Newtonsoft.Json/Serialization/JsonProperty.cs b/Src/Newtonsoft.Json/Serialization/JsonProperty.cs index 38fe85169..183a5a726 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonProperty.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonProperty.cs @@ -24,6 +24,7 @@ #endregion using System; +using System.Diagnostics; using System.Reflection; using Newtonsoft.Json.Utilities; @@ -41,20 +42,20 @@ public class JsonProperty internal Required? _required; internal bool _hasExplicitDefaultValue; - private object _defaultValue; + private object? _defaultValue; private bool _hasGeneratedDefaultValue; - private string _propertyName; + private string? _propertyName; internal bool _skipPropertyNameEscape; - private Type _propertyType; + private Type? _propertyType; // use to cache contract during deserialization - internal JsonContract PropertyContract { get; set; } + internal JsonContract? PropertyContract { get; set; } /// /// Gets or sets the name of the property. /// /// The name of the property. - public string PropertyName + public string? PropertyName { get => _propertyName; set @@ -68,7 +69,7 @@ public string PropertyName /// Gets or sets the type that declared this property. /// /// The type that declared this property. - public Type DeclaringType { get; set; } + public Type? DeclaringType { get; set; } /// /// Gets or sets the order of serialization of a member. @@ -80,25 +81,25 @@ public string PropertyName /// Gets or sets the name of the underlying member or parameter. /// /// The name of the underlying member or parameter. - public string UnderlyingName { get; set; } + public string? UnderlyingName { get; set; } /// /// Gets the that will get and set the during serialization. /// /// The that will get and set the during serialization. - public IValueProvider ValueProvider { get; set; } + public IValueProvider? ValueProvider { get; set; } /// /// Gets or sets the for this property. /// /// The for this property. - public IAttributeProvider AttributeProvider { get; set; } + public IAttributeProvider? AttributeProvider { get; set; } /// /// Gets or sets the type of the property. /// /// The type of the property. - public Type PropertyType + public Type? PropertyType { get => _propertyType; set @@ -116,14 +117,14 @@ public Type PropertyType /// If set this converter takes precedence over the contract converter for the property type. /// /// The converter. - public JsonConverter Converter { get; set; } + public JsonConverter? Converter { get; set; } /// /// Gets or sets the member converter. /// /// The member converter. [Obsolete("MemberConverter is obsolete. Use Converter instead.")] - public JsonConverter MemberConverter + public JsonConverter? MemberConverter { get => Converter; set => Converter = value; @@ -157,7 +158,7 @@ public JsonConverter MemberConverter /// Gets the default value. /// /// The default value. - public object DefaultValue + public object? DefaultValue { get { @@ -175,7 +176,7 @@ public object DefaultValue } } - internal object GetResolvedDefaultValue() + internal object? GetResolvedDefaultValue() { if (_propertyType == null) { @@ -184,7 +185,7 @@ internal object GetResolvedDefaultValue() if (!_hasExplicitDefaultValue && !_hasGeneratedDefaultValue) { - _defaultValue = ReflectionUtils.GetDefaultValue(PropertyType); + _defaultValue = ReflectionUtils.GetDefaultValue(_propertyType); _hasGeneratedDefaultValue = true; } @@ -248,25 +249,25 @@ public Required Required /// Gets or sets a predicate used to determine whether the property should be serialized. /// /// A predicate used to determine whether the property should be serialized. - public Predicate ShouldSerialize { get; set; } + public Predicate? ShouldSerialize { get; set; } /// /// Gets or sets a predicate used to determine whether the property should be deserialized. /// /// A predicate used to determine whether the property should be deserialized. - public Predicate ShouldDeserialize { get; set; } + public Predicate? ShouldDeserialize { get; set; } /// /// Gets or sets a predicate used to determine whether the property should be serialized. /// /// A predicate used to determine whether the property should be serialized. - public Predicate GetIsSpecified { get; set; } + public Predicate? GetIsSpecified { get; set; } /// /// Gets or sets an action used to set whether the property has been deserialized. /// /// An action used to set whether the property has been deserialized. - public Action SetIsSpecified { get; set; } + public Action? SetIsSpecified { get; set; } /// /// Returns a that represents this instance. @@ -276,14 +277,14 @@ public Required Required /// public override string ToString() { - return PropertyName; + return PropertyName ?? string.Empty; } /// /// Gets or sets the converter used when serializing the property's collection items. /// /// The collection's items converter. - public JsonConverter ItemConverter { get; set; } + public JsonConverter? ItemConverter { get; set; } /// /// Gets or sets whether this property's collection items are serialized as a reference. @@ -305,13 +306,16 @@ public override string ToString() internal void WritePropertyName(JsonWriter writer) { + string? propertyName = PropertyName; + MiscellaneousUtils.Assert(propertyName != null); + if (_skipPropertyNameEscape) { - writer.WritePropertyName(PropertyName, false); + writer.WritePropertyName(propertyName, false); } else { - writer.WritePropertyName(PropertyName); + writer.WritePropertyName(propertyName); } } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs b/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs index 9bb5a5cf2..684be0d3b 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs @@ -29,6 +29,9 @@ using System.Collections.ObjectModel; using Newtonsoft.Json.Utilities; using System.Globalization; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace Newtonsoft.Json.Serialization { @@ -61,7 +64,7 @@ public JsonPropertyCollection(Type type) /// The key for the specified element. protected override string GetKeyForItem(JsonProperty item) { - return item.PropertyName; + return item.PropertyName!; } /// @@ -70,6 +73,8 @@ protected override string GetKeyForItem(JsonProperty item) /// The property to add to the collection. public void AddProperty(JsonProperty property) { + MiscellaneousUtils.Assert(property.PropertyName != null); + if (Contains(property.PropertyName)) { // don't overwrite existing property with ignored property @@ -129,9 +134,9 @@ public void AddProperty(JsonProperty property) /// /// Name of the property. /// A matching property if found. - public JsonProperty GetClosestMatchProperty(string propertyName) + public JsonProperty? GetClosestMatchProperty(string propertyName) { - JsonProperty property = GetProperty(propertyName, StringComparison.Ordinal); + JsonProperty? property = GetProperty(propertyName, StringComparison.Ordinal); if (property == null) { property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase); @@ -140,7 +145,7 @@ public JsonProperty GetClosestMatchProperty(string propertyName) return property; } - private bool TryGetValue(string key, out JsonProperty item) + private bool TryGetProperty(string key, [NotNullWhen(true)]out JsonProperty? item) { if (Dictionary == null) { @@ -157,12 +162,12 @@ private bool TryGetValue(string key, out JsonProperty item) /// The name of the property to get. /// Type property name string comparison. /// A matching property if found. - public JsonProperty GetProperty(string propertyName, StringComparison comparisonType) + public JsonProperty? GetProperty(string propertyName, StringComparison comparisonType) { // KeyedCollection has an ordinal comparer if (comparisonType == StringComparison.Ordinal) { - if (TryGetValue(propertyName, out JsonProperty property)) + if (TryGetProperty(propertyName, out JsonProperty? property)) { return property; } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs index 73d8670bd..1cdb0c5ae 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalBase.cs @@ -35,7 +35,7 @@ internal abstract class JsonSerializerInternalBase { private class ReferenceEqualsEqualityComparer : IEqualityComparer { - bool IEqualityComparer.Equals(object x, object y) + bool IEqualityComparer.Equals(object? x, object? y) { return ReferenceEquals(x, y); } @@ -47,12 +47,12 @@ int IEqualityComparer.GetHashCode(object obj) } } - private ErrorContext _currentErrorContext; - private BidirectionalDictionary _mappings; + private ErrorContext? _currentErrorContext; + private BidirectionalDictionary? _mappings; internal readonly JsonSerializer Serializer; - internal readonly ITraceWriter TraceWriter; - protected JsonSerializerProxy InternalSerializer; + internal readonly ITraceWriter? TraceWriter; + protected JsonSerializerProxy? InternalSerializer; protected JsonSerializerInternalBase(JsonSerializer serializer) { @@ -81,7 +81,7 @@ internal BidirectionalDictionary DefaultReferenceMappings } } - protected NullValueHandling ResolvedNullValueHandling(JsonObjectContract containerContract, JsonProperty property) + protected NullValueHandling ResolvedNullValueHandling(JsonObjectContract? containerContract, JsonProperty property) { NullValueHandling resolvedNullValueHandling = property.NullValueHandling @@ -91,7 +91,7 @@ protected NullValueHandling ResolvedNullValueHandling(JsonObjectContract contain return resolvedNullValueHandling; } - private ErrorContext GetErrorContext(object currentObject, object member, string path, Exception error) + private ErrorContext GetErrorContext(object? currentObject, object? member, string path, Exception error) { if (_currentErrorContext == null) { @@ -116,7 +116,7 @@ protected void ClearErrorContext() _currentErrorContext = null; } - protected bool IsErrorHandled(object currentObject, JsonContract contract, object keyValue, IJsonLineInfo lineInfo, string path, Exception ex) + protected bool IsErrorHandled(object? currentObject, JsonContract? contract, object? keyValue, IJsonLineInfo? lineInfo, string path, Exception ex) { ErrorContext errorContext = GetErrorContext(currentObject, keyValue, path, ex); diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index d0ee4d526..72bc0cca2 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -40,11 +40,12 @@ using System.Runtime.Serialization; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Utilities; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Newtonsoft.Json.Serialization @@ -93,10 +94,10 @@ public void Populate(JsonReader reader, object target) { reader.ReadAndAssert(); - string id = null; + string? id = null; if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore && reader.TokenType == JsonToken.PropertyName - && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) + && string.Equals(reader.Value!.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); id = reader.Value?.ToString(); @@ -123,28 +124,33 @@ public void Populate(JsonReader reader, object target) } } - private JsonContract GetContractSafe(Type type) + private JsonContract? GetContractSafe(Type? type) { if (type == null) { return null; } + return GetContract(type); + } + + private JsonContract GetContract(Type type) + { return Serializer._contractResolver.ResolveContract(type); } - public object Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent) + public object? Deserialize(JsonReader reader, Type? objectType, bool checkAdditionalContent) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } - JsonContract contract = GetContractSafe(objectType); + JsonContract? contract = GetContractSafe(objectType); try { - JsonConverter converter = GetConverter(contract, null, null, null); + JsonConverter? converter = GetConverter(contract, null, null, null); if (reader.TokenType == JsonToken.None && !reader.ReadForType(contract, converter != null)) { @@ -156,11 +162,11 @@ public object Deserialize(JsonReader reader, Type objectType, bool checkAddition return null; } - object deserializedValue; + object? deserializedValue; if (converter != null && converter.CanRead) { - deserializedValue = DeserializeConvertable(converter, reader, objectType, null); + deserializedValue = DeserializeConvertable(converter, reader, objectType!, null); } else { @@ -208,7 +214,7 @@ private JsonSerializerProxy GetInternalSerializer() return InternalSerializer; } - private JToken CreateJToken(JsonReader reader, JsonContract contract) + private JToken? CreateJToken(JsonReader reader, JsonContract? contract) { ValidationUtils.ArgumentNotNull(reader, nameof(reader)); @@ -225,13 +231,22 @@ private JToken CreateJToken(JsonReader reader, JsonContract contract) } } - JToken token; + JToken? token; using (JTokenWriter writer = new JTokenWriter()) { writer.WriteToken(reader); token = writer.Token; } + if (contract != null && token != null) + { + if (!contract.UnderlyingType.IsAssignableFrom(token.GetType())) + { + throw JsonSerializationException.Create(reader, "Deserialized JSON type '{0}' is not compatible with expected type '{1}'." + .FormatWith(CultureInfo.InvariantCulture, token.GetType().FullName, contract.UnderlyingType.FullName)); + } + } + return token; } @@ -248,7 +263,7 @@ private JToken CreateJObject(JsonReader reader) { if (reader.TokenType == JsonToken.PropertyName) { - string propertyName = (string)reader.Value; + string propertyName = (string)reader.Value!; if (!reader.ReadAndMoveToContent()) { break; @@ -269,7 +284,7 @@ private JToken CreateJObject(JsonReader reader) else { writer.WriteEndObject(); - return writer.Token; + return writer.Token!; } } while (reader.Read()); @@ -277,7 +292,7 @@ private JToken CreateJObject(JsonReader reader) } } - private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue) + private object? CreateValueInternal(JsonReader reader, Type? objectType, JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue) { if (contract != null && contract.ContractType == JsonContractType.Linq) { @@ -301,7 +316,7 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr case JsonToken.Bytes: return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.String: - string s = (string)reader.Value; + string s = (string)reader.Value!; // string that needs to be returned as a byte array should be base 64 decoded if (objectType == typeof(byte[])) @@ -317,7 +332,7 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr return EnsureType(reader, s, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.StartConstructor: - string constructorName = reader.Value.ToString(); + string constructorName = reader.Value!.ToString()!; return EnsureType(reader, constructorName, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.Null: @@ -331,7 +346,7 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType); case JsonToken.Raw: - return new JRaw((string)reader.Value); + return new JRaw((string?)reader.Value); case JsonToken.Comment: // ignore break; @@ -343,9 +358,9 @@ private object CreateValueInternal(JsonReader reader, Type objectType, JsonContr throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); } - private static bool CoerceEmptyStringToNull(Type objectType, JsonContract contract, string s) + private static bool CoerceEmptyStringToNull(Type? objectType, JsonContract? contract, string s) { - return string.IsNullOrEmpty(s) && objectType != null && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable; + return StringUtils.IsNullOrEmpty(s) && objectType != null && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable; } internal string GetExpectedDescription(JsonContract contract) @@ -372,9 +387,9 @@ internal string GetExpectedDescription(JsonContract contract) } } - private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract, JsonProperty containerProperty) + private JsonConverter? GetConverter(JsonContract? contract, JsonConverter? memberConverter, JsonContainerContract? containerContract, JsonProperty? containerProperty) { - JsonConverter converter = null; + JsonConverter? converter = null; if (memberConverter != null) { // member attribute converter @@ -390,13 +405,12 @@ private JsonConverter GetConverter(JsonContract contract, JsonConverter memberCo } else if (contract != null) { - JsonConverter matchingConverter; if (contract.Converter != null) { // class attribute converter converter = contract.Converter; } - else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null) + else if (Serializer.GetMatchingConverter(contract.UnderlyingType) is JsonConverter matchingConverter) { // passed in converters converter = matchingConverter; @@ -410,10 +424,10 @@ private JsonConverter GetConverter(JsonContract contract, JsonConverter memberCo return converter; } - private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue) + private object? CreateObject(JsonReader reader, Type? objectType, JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue) { - string id; - Type resolvedObjectType = objectType; + string? id; + Type? resolvedObjectType = objectType; if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.Ignore) { @@ -440,7 +454,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con reader = tokenReader; } - if (ReadMetadataPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object newValue, out id)) + if (ReadMetadataPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object? newValue, out id)) { return newValue; } @@ -448,7 +462,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con else { reader.ReadAndAssert(); - if (ReadMetadataProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object newValue, out id)) + if (ReadMetadataProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object? newValue, out id)) { return newValue; } @@ -459,6 +473,9 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con return CreateJObject(reader); } + MiscellaneousUtils.Assert(resolvedObjectType != null); + MiscellaneousUtils.Assert(contract != null); + switch (contract.ContractType) { case JsonContractType.Object: @@ -490,7 +507,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con // if the content is inside $value then read past it if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore && reader.TokenType == JsonToken.PropertyName - && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal)) + && string.Equals(reader.Value!.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); @@ -501,7 +518,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con throw JsonSerializationException.Create(reader, "Unexpected token when deserializing primitive value: " + reader.TokenType); } - object value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue); + object? value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue); reader.ReadAndAssert(); return value; @@ -544,7 +561,7 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con if (createdFromNonDefaultCreator) { - ObjectConstructor creator = dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator; + ObjectConstructor creator = (dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator)!; return creator(dictionary); } @@ -553,8 +570,8 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con return wrappedDictionary.UnderlyingDictionary; } - targetDictionary = dictionary; - } + targetDictionary = dictionary; + } else { targetDictionary = PopulateDictionary(dictionaryContract.ShouldCreateWrapper || !(existingValue is IDictionary) ? dictionaryContract.CreateWrapper(existingValue) : (IDictionary)existingValue, reader, dictionaryContract, member, id); @@ -581,38 +598,29 @@ private object CreateObject(JsonReader reader, Type objectType, JsonContract con throw JsonSerializationException.Create(reader, message); } - private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id) + private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type? objectType, ref JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue, out object? newValue, out string? id) { id = null; newValue = null; if (reader.TokenType == JsonToken.StartObject) { - JObject current = (JObject)reader.CurrentToken; + JObject current = (JObject)reader.CurrentToken!; - JToken refToken = current[JsonTypeReflector.RefPropertyName]; - if (refToken != null) + JProperty? refProperty = current.Property(JsonTypeReflector.RefPropertyName, StringComparison.Ordinal); + if (refProperty != null) { + JToken refToken = refProperty.Value; if (refToken.Type != JTokenType.String && refToken.Type != JTokenType.Null) { throw JsonSerializationException.Create(refToken, refToken.Path, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null); } - JToken property = refToken.Parent; - JToken additionalContent = null; - if (property.Next != null) - { - additionalContent = property.Next; - } - else if (property.Previous != null) - { - additionalContent = property.Previous; - } - - string reference = (string)refToken; + string? reference = (string?)refProperty; if (reference != null) { + JToken? additionalContent = refProperty.Next ?? refProperty.Previous; if (additionalContent != null) { throw JsonSerializationException.Create(additionalContent, additionalContent.Path, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null); @@ -629,15 +637,15 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp return true; } } - JToken typeToken = current[JsonTypeReflector.TypePropertyName]; + JToken? typeToken = current[JsonTypeReflector.TypePropertyName]; if (typeToken != null) { - string qualifiedTypeName = (string)typeToken; + string? qualifiedTypeName = (string?)typeToken; JsonReader typeTokenReader = typeToken.CreateReader(); typeTokenReader.ReadAndAssert(); - ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName); + ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName!); - JToken valueToken = current[JsonTypeReflector.ValuePropertyName]; + JToken? valueToken = current[JsonTypeReflector.ValuePropertyName]; if (valueToken != null) { while (true) @@ -645,7 +653,7 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp reader.ReadAndAssert(); if (reader.TokenType == JsonToken.PropertyName) { - if ((string)reader.Value == JsonTypeReflector.ValuePropertyName) + if ((string)reader.Value! == JsonTypeReflector.ValuePropertyName) { return false; } @@ -656,12 +664,12 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp } } } - JToken idToken = current[JsonTypeReflector.IdPropertyName]; + JToken? idToken = current[JsonTypeReflector.IdPropertyName]; if (idToken != null) { - id = (string)idToken; + id = (string?)idToken; } - JToken valuesToken = current[JsonTypeReflector.ArrayValuesPropertyName]; + JToken? valuesToken = current[JsonTypeReflector.ArrayValuesPropertyName]; if (valuesToken != null) { JsonReader listReader = valuesToken.CreateReader(); @@ -677,14 +685,14 @@ private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectTyp return false; } - private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id) + private bool ReadMetadataProperties(JsonReader reader, ref Type? objectType, ref JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, object? existingValue, out object? newValue, out string? id) { id = null; newValue = null; if (reader.TokenType == JsonToken.PropertyName) { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (propertyName.Length > 0 && propertyName[0] == '$') { @@ -694,7 +702,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref do { - propertyName = reader.Value.ToString(); + propertyName = reader.Value!.ToString()!; if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal)) { @@ -704,7 +712,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref throw JsonSerializationException.Create(reader, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName)); } - string reference = reader.Value?.ToString(); + string? reference = reader.Value?.ToString(); reader.ReadAndAssert(); @@ -719,7 +727,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { - TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null); + TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue!.GetType())), null); } return true; @@ -732,7 +740,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); - string qualifiedTypeName = reader.Value.ToString(); + string qualifiedTypeName = reader.Value!.ToString()!; ResolveTypeName(reader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName); @@ -752,7 +760,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal)) { reader.ReadAndAssert(); - object list = CreateList(reader, objectType, contract, member, existingValue, id); + object? list = CreateList(reader, objectType, contract, member, existingValue, id); reader.ReadAndAssert(); newValue = list; return true; @@ -767,7 +775,7 @@ private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref return false; } - private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, string qualifiedTypeName) + private void ResolveTypeName(JsonReader reader, ref Type? objectType, ref JsonContract? contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerMember, string qualifiedTypeName) { TypeNameHandling resolvedTypeNameHandling = member?.TypeNameHandling @@ -777,7 +785,7 @@ private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonCon if (resolvedTypeNameHandling != TypeNameHandling.None) { - StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName); + StructMultiKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName); Type specifiedType; try @@ -809,7 +817,7 @@ private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonCon } objectType = specifiedType; - contract = GetContractSafe(specifiedType); + contract = GetContract(specifiedType); } } @@ -832,15 +840,18 @@ private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType return arrayContract; } - private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id) + private object? CreateList(JsonReader reader, Type? objectType, JsonContract? contract, JsonProperty? member, object? existingValue, string? id) { - object value; + object? value; if (HasNoDefinedType(contract)) { return CreateJToken(reader, contract); } + MiscellaneousUtils.Assert(objectType != null); + MiscellaneousUtils.Assert(contract != null); + JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract); if (existingValue == null) @@ -883,17 +894,17 @@ private object CreateList(JsonReader reader, Type objectType, JsonContract contr { if (arrayContract.IsMultidimensionalArray) { - list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType, contract.CreatedType.GetArrayRank()); + list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType!, contract.CreatedType.GetArrayRank()); } else if (arrayContract.IsArray) { - Array a = Array.CreateInstance(arrayContract.CollectionItemType, list.Count); + Array a = Array.CreateInstance(arrayContract.CollectionItemType!, list.Count); list.CopyTo(a, 0); list = a; } else { - ObjectConstructor creator = arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator; + ObjectConstructor creator = (arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator)!; return creator(list); } @@ -918,7 +929,7 @@ private object CreateList(JsonReader reader, Type objectType, JsonContract contr return value; } - private bool HasNoDefinedType(JsonContract contract) + private bool HasNoDefinedType(JsonContract? contract) { return (contract == null || contract.UnderlyingType == typeof(object) || contract.ContractType == JsonContractType.Linq #if HAVE_DYNAMIC @@ -927,14 +938,15 @@ private bool HasNoDefinedType(JsonContract contract) ); } - private object EnsureType(JsonReader reader, object value, CultureInfo culture, JsonContract contract, Type targetType) + private object? EnsureType(JsonReader reader, object? value, CultureInfo culture, JsonContract? contract, Type? targetType) { if (targetType == null) { return value; } - Type valueType = ReflectionUtils.GetObjectType(value); + MiscellaneousUtils.Assert(contract != null); + Type? valueType = ReflectionUtils.GetObjectType(value); // type of value and type of target don't match // attempt to convert value's type to target's type @@ -955,11 +967,15 @@ private object EnsureType(JsonReader reader, object value, CultureInfo culture, { if (value is string s) { - return EnumUtils.ParseEnum(contract.NonNullableUnderlyingType, null, s, false); + return EnumUtils.ParseEnum( + contract.NonNullableUnderlyingType, + null, + s, + false); } if (ConvertUtils.IsInteger(primitiveContract.TypeCode)) { - return Enum.ToObject(contract.NonNullableUnderlyingType, value); + return Enum.ToObject(contract.NonNullableUnderlyingType, value!); } } else if (contract.NonNullableUnderlyingType == typeof(DateTime)) @@ -993,7 +1009,7 @@ private object EnsureType(JsonReader reader, object value, CultureInfo culture, return value; } - private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target) + private bool SetPropertyValue(JsonProperty property, JsonConverter? propertyConverter, JsonContainerContract? containerContract, JsonProperty? containerProperty, JsonReader reader, object target) { bool skipSettingProperty = CalculatePropertyDetails( property, @@ -1003,8 +1019,8 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve reader, target, out bool useExistingValue, - out object currentValue, - out JsonContract propertyContract, + out object? currentValue, + out JsonContract? propertyContract, out bool gottenCurrentValue, out bool ignoredValue); @@ -1020,16 +1036,16 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve return false; } - object value; + object? value; if (propertyConverter != null && propertyConverter.CanRead) { - if (!gottenCurrentValue && target != null && property.Readable) + if (!gottenCurrentValue && property.Readable) { - currentValue = property.ValueProvider.GetValue(target); + currentValue = property.ValueProvider!.GetValue(target); } - value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, currentValue); + value = DeserializeConvertable(propertyConverter, reader, property.PropertyType!, currentValue); } else { @@ -1042,7 +1058,7 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve if ((!useExistingValue || value != currentValue) && ShouldSetPropertyValue(property, containerContract as JsonObjectContract, value)) { - property.ValueProvider.SetValue(target, value); + property.ValueProvider!.SetValue(target, value); if (property.SetIsSpecified != null) { @@ -1063,14 +1079,14 @@ private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConve private bool CalculatePropertyDetails( JsonProperty property, - ref JsonConverter propertyConverter, - JsonContainerContract containerContract, - JsonProperty containerProperty, + ref JsonConverter? propertyConverter, + JsonContainerContract? containerContract, + JsonProperty? containerProperty, JsonReader reader, object target, out bool useExistingValue, - out object currentValue, - out JsonContract propertyContract, + out object? currentValue, + out JsonContract? propertyContract, out bool gottenCurrentValue, out bool ignoredValue) { @@ -1097,14 +1113,15 @@ private bool CalculatePropertyDetails( if ((objectCreationHandling != ObjectCreationHandling.Replace) && (tokenType == JsonToken.StartArray || tokenType == JsonToken.StartObject || propertyConverter != null) - && property.Readable) + && property.Readable + && property.PropertyContract?.ContractType != JsonContractType.Linq) { - currentValue = property.ValueProvider.GetValue(target); + currentValue = property.ValueProvider!.GetValue(target); gottenCurrentValue = true; if (currentValue != null) { - propertyContract = GetContractSafe(currentValue.GetType()); + propertyContract = GetContract(currentValue.GetType()); useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType()); } @@ -1143,7 +1160,7 @@ private bool CalculatePropertyDetails( } else { - propertyContract = GetContractSafe(currentValue.GetType()); + propertyContract = GetContract(currentValue.GetType()); if (propertyContract != property.PropertyContract) { @@ -1176,7 +1193,7 @@ private bool HasFlag(DefaultValueHandling value, DefaultValueHandling flag) return ((value & flag) == flag); } - private bool ShouldSetPropertyValue(JsonProperty property, JsonObjectContract contract, object value) + private bool ShouldSetPropertyValue(JsonProperty property, JsonObjectContract? contract, object? value) { if (value == null && ResolvedNullValueHandling(contract, property) == NullValueHandling.Ignore) { @@ -1334,7 +1351,7 @@ private void OnDeserialized(JsonReader reader, JsonContract contract, object val contract.InvokeOnDeserialized(value, Serializer._context); } - private object PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id) + private object PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty? containerProperty, string? id) { object underlyingDictionary = dictionary is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : dictionary; @@ -1357,7 +1374,7 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso contract.ItemContract = GetContractSafe(contract.DictionaryValueType); } - JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty); + JsonConverter? dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty); PrimitiveTypeCode keyTypeCode = (contract.KeyContract is JsonPrimitiveContract keyContract) ? keyContract.TypeCode : PrimitiveTypeCode.Empty; bool finished = false; @@ -1366,8 +1383,8 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso switch (reader.TokenType) { case JsonToken.PropertyName: - object keyValue = reader.Value; - if (CheckPropertyName(reader, keyValue.ToString())) + object keyValue = reader.Value!; + if (CheckPropertyName(reader, keyValue.ToString()!)) { continue; } @@ -1382,23 +1399,25 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso case PrimitiveTypeCode.DateTime: case PrimitiveTypeCode.DateTimeNullable: { - keyValue = DateTimeUtils.TryParseDateTime(keyValue.ToString(), reader.DateTimeZoneHandling, reader.DateFormatString, reader.Culture, out DateTime dt) + keyValue = DateTimeUtils.TryParseDateTime(keyValue.ToString()!, reader.DateTimeZoneHandling, reader.DateFormatString, reader.Culture, out DateTime dt) ? dt - : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType); + : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType)!; break; } #if HAVE_DATE_TIME_OFFSET case PrimitiveTypeCode.DateTimeOffset: case PrimitiveTypeCode.DateTimeOffsetNullable: { - keyValue = DateTimeUtils.TryParseDateTimeOffset(keyValue.ToString(), reader.DateFormatString, reader.Culture, out DateTimeOffset dt) + keyValue = DateTimeUtils.TryParseDateTimeOffset(keyValue.ToString()!, reader.DateFormatString, reader.Culture, out DateTimeOffset dt) ? dt - : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType); + : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType)!; break; } #endif default: - keyValue = EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType); + keyValue = contract.KeyContract != null && contract.KeyContract.IsEnum + ? EnumUtils.ParseEnum(contract.KeyContract.NonNullableUnderlyingType, (Serializer._contractResolver as DefaultContractResolver)?.NamingStrategy, keyValue.ToString()!, false) + : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType)!; break; } } @@ -1412,10 +1431,10 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object."); } - object itemValue; + object? itemValue; if (dictionaryValueConverter != null && dictionaryValueConverter.CanRead) { - itemValue = DeserializeConvertable(dictionaryValueConverter, reader, contract.DictionaryValueType, null); + itemValue = DeserializeConvertable(dictionaryValueConverter, reader, contract.DictionaryValueType!, null); } else { @@ -1455,7 +1474,7 @@ private object PopulateDictionary(IDictionary dictionary, JsonReader reader, Jso return underlyingDictionary; } - private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id) + private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty? containerProperty, string? id) { int rank = contract.UnderlyingType.GetArrayRank(); @@ -1466,8 +1485,8 @@ private object PopulateMultidimensionalArray(IList list, JsonReader reader, Json OnDeserializing(reader, contract, list); - JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType); - JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty); + JsonContract? collectionItemContract = GetContractSafe(contract.CollectionItemType); + JsonConverter? collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty); int? previousErrorIndex = null; Stack listStack = new Stack(); @@ -1495,11 +1514,11 @@ private object PopulateMultidimensionalArray(IList list, JsonReader reader, Json case JsonToken.Comment: break; default: - object value; + object? value; if (collectionItemConverter != null && collectionItemConverter.CanRead) { - value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null); + value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType!, null); } else { @@ -1586,7 +1605,7 @@ private object PopulateMultidimensionalArray(IList list, JsonReader reader, Json return list; } - private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object currentObject, string message) + private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object? currentObject, string message) { try { @@ -1605,8 +1624,9 @@ private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contrac } } - private object PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id) + private object PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty? containerProperty, string? id) { +#pragma warning disable CS8600, CS8602, CS8603, CS8604 object underlyingList = list is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : list; if (id != null) @@ -1630,7 +1650,7 @@ private object PopulateList(IList list, JsonReader reader, JsonArrayContract con contract.ItemContract = GetContractSafe(contract.CollectionItemType); } - JsonConverter collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty); + JsonConverter? collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty); int? previousErrorIndex = null; @@ -1649,7 +1669,7 @@ private object PopulateList(IList list, JsonReader reader, JsonArrayContract con case JsonToken.Comment: break; default: - object value; + object? value; if (collectionItemConverter != null && collectionItemConverter.CanRead) { @@ -1702,10 +1722,11 @@ private object PopulateList(IList list, JsonReader reader, JsonArrayContract con OnDeserialized(reader, contract, underlyingList); return underlyingList; +#pragma warning restore CS8600, CS8602, CS8603, CS8604 } #if HAVE_BINARY_SERIALIZATION - private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, JsonProperty member, string id) + private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, JsonProperty? member, string? id) { Type objectType = contract.UnderlyingType; @@ -1731,7 +1752,7 @@ private object CreateISerializable(JsonReader reader, JsonISerializableContract switch (reader.TokenType) { case JsonToken.PropertyName: - string memberName = reader.Value.ToString(); + string memberName = reader.Value!.ToString()!; if (!reader.Read()) { throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); @@ -1777,15 +1798,16 @@ private object CreateISerializable(JsonReader reader, JsonISerializableContract return createdObject; } - internal object CreateISerializableItem(JToken token, Type type, JsonISerializableContract contract, JsonProperty member) + internal object? CreateISerializableItem(JToken token, Type type, JsonISerializableContract contract, JsonProperty? member) { - JsonContract itemContract = GetContractSafe(type); - JsonConverter itemConverter = GetConverter(itemContract, null, contract, member); + JsonContract? itemContract = GetContractSafe(type); + JsonConverter? itemConverter = GetConverter(itemContract, null, contract, member); JsonReader tokenReader = token.CreateReader(); + tokenReader.MaxDepth = Serializer.MaxDepth; tokenReader.ReadAndAssert(); // Move to first token - object result; + object? result; if (itemConverter != null && itemConverter.CanRead) { result = DeserializeConvertable(itemConverter, tokenReader, type, null); @@ -1800,7 +1822,7 @@ internal object CreateISerializableItem(JToken token, Type type, JsonISerializab #endif #if HAVE_DYNAMIC - private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, JsonProperty member, string id) + private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, JsonProperty? member, string? id) { IDynamicMetaObjectProvider newObject; @@ -1834,7 +1856,7 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js switch (reader.TokenType) { case JsonToken.PropertyName: - string memberName = reader.Value.ToString(); + string memberName = reader.Value!.ToString()!; try { @@ -1844,7 +1866,7 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js } // first attempt to find a settable property, otherwise fall back to a dynamic set without type - JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName); + JsonProperty? property = contract.Properties.GetClosestMatchProperty(memberName); if (property != null && property.Writable && !property.Ignored) { @@ -1853,7 +1875,7 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js property.PropertyContract = GetContractSafe(property.PropertyType); } - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, null, null); + JsonConverter? propertyConverter = GetConverter(property.PropertyContract, property.Converter, null, null); if (!SetPropertyValue(property, propertyConverter, null, member, reader, newObject)) { @@ -1862,15 +1884,15 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js } else { - Type t = (JsonTokenUtils.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType : typeof(IDynamicMetaObjectProvider); + Type t = (JsonTokenUtils.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType! : typeof(IDynamicMetaObjectProvider); - JsonContract dynamicMemberContract = GetContractSafe(t); - JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member); + JsonContract? dynamicMemberContract = GetContractSafe(t); + JsonConverter? dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member); - object value; + object? value; if (dynamicMemberConverter != null && dynamicMemberConverter.CanRead) { - value = DeserializeConvertable(dynamicMemberConverter, reader, t, null); + value = DeserializeConvertable(dynamicMemberConverter!, reader, t, null); } else { @@ -1913,15 +1935,20 @@ private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, Js internal class CreatorPropertyContext { - public string Name; - public JsonProperty Property; - public JsonProperty ConstructorProperty; + public readonly string Name; + public JsonProperty? Property; + public JsonProperty? ConstructorProperty; public PropertyPresence? Presence; - public object Value; + public object? Value; public bool Used; + + public CreatorPropertyContext(string name) + { + Name = name; + } } - private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor creator, string id) + private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty? containerProperty, ObjectConstructor creator, string? id) { ValidationUtils.ArgumentNotNull(creator, nameof(creator)); @@ -1949,10 +1976,9 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj { if (propertyContexts.All(p => p.Property != property)) { - propertyContexts.Add(new CreatorPropertyContext + propertyContexts.Add(new CreatorPropertyContext(property.PropertyName!) { Property = property, - Name = property.PropertyName, Presence = PropertyPresence.None }); } @@ -1960,7 +1986,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj } } - object[] creatorParameterValues = new object[contract.CreatorParameters.Count]; + object?[] creatorParameterValues = new object?[contract.CreatorParameters.Count]; foreach (CreatorPropertyContext context in propertyContexts) { @@ -1969,7 +1995,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj { if (context.Property != null && context.Presence == null) { - object v = context.Value; + object? v = context.Value; PropertyPresence propertyPresence; if (v == null) { @@ -1990,10 +2016,10 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj } } - JsonProperty constructorProperty = context.ConstructorProperty; + JsonProperty? constructorProperty = context.ConstructorProperty; if (constructorProperty == null && context.Property != null) { - constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, context.Property.UnderlyingName); + constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName!, context.Property.UnderlyingName!); } if (constructorProperty != null && !constructorProperty.Ignored) @@ -2015,7 +2041,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj reader, constructorProperty.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, - constructorProperty.PropertyContract, + constructorProperty.PropertyContract!, constructorProperty.PropertyType); } } @@ -2049,17 +2075,17 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj } JsonProperty property = context.Property; - object value = context.Value; + object? value = context.Value; if (ShouldSetPropertyValue(property, contract, value)) { - property.ValueProvider.SetValue(createdObject, value); + property.ValueProvider!.SetValue(createdObject, value); context.Used = true; } else if (!property.Writable && value != null) { // handle readonly collection/dictionary properties - JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType); + JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType!); if (propertyContract.ContractType == JsonContractType.Array) { @@ -2067,15 +2093,22 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj if (propertyArrayContract.CanDeserialize && !propertyArrayContract.IsReadOnlyOrFixedSize) { - object createdObjectCollection = property.ValueProvider.GetValue(createdObject); + object? createdObjectCollection = property.ValueProvider!.GetValue(createdObject); if (createdObjectCollection != null) { + propertyArrayContract = (JsonArrayContract)GetContract(createdObjectCollection.GetType()); + IList createdObjectCollectionWrapper = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(createdObjectCollection) : (IList)createdObjectCollection; - IList newValues = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(value) : (IList)value; - foreach (object newValue in newValues) + // Don't attempt to populate array/read-only list + if (!createdObjectCollectionWrapper.IsFixedSize) { - createdObjectCollectionWrapper.Add(newValue); + IList newValues = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(value) : (IList)value; + + foreach (object newValue in newValues) + { + createdObjectCollectionWrapper.Add(newValue); + } } } } @@ -2086,7 +2119,7 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj if (!dictionaryContract.IsReadOnlyOrFixedSize) { - object createdObjectDictionary = property.ValueProvider.GetValue(createdObject); + object? createdObjectDictionary = property.ValueProvider!.GetValue(createdObject); if (createdObjectDictionary != null) { IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary; @@ -2149,14 +2182,14 @@ private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObj return createdObject; } - private object DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object existingValue) + private object? DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object? existingValue) { if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, objectType, converter.GetType())), null); } - object value = converter.ReadJson(reader, objectType, existingValue, GetInternalSerializer()); + object? value = converter.ReadJson(reader, objectType, existingValue, GetInternalSerializer()); if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info) { @@ -2166,7 +2199,7 @@ private object DeserializeConvertable(JsonConverter converter, JsonReader reader return value; } - private List ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType) + private List ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty? containerProperty, JsonReader reader, Type objectType) { List propertyValues = new List(); bool exit = false; @@ -2175,41 +2208,50 @@ private List ResolvePropertyAndCreatorValues(JsonObjectC switch (reader.TokenType) { case JsonToken.PropertyName: - string memberName = reader.Value.ToString(); + string memberName = reader.Value!.ToString()!; - CreatorPropertyContext creatorPropertyContext = new CreatorPropertyContext + CreatorPropertyContext creatorPropertyContext = new CreatorPropertyContext(memberName) { - Name = memberName, ConstructorProperty = contract.CreatorParameters.GetClosestMatchProperty(memberName), Property = contract.Properties.GetClosestMatchProperty(memberName) }; propertyValues.Add(creatorPropertyContext); - JsonProperty property = creatorPropertyContext.ConstructorProperty ?? creatorPropertyContext.Property; - if (property != null && !property.Ignored) + JsonProperty? property = creatorPropertyContext.ConstructorProperty ?? creatorPropertyContext.Property; + if (property != null) { - if (property.PropertyContract == null) + if (!property.Ignored) { - property.PropertyContract = GetContractSafe(property.PropertyType); - } + if (property.PropertyContract == null) + { + property.PropertyContract = GetContractSafe(property.PropertyType); + } - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, containerProperty); + JsonConverter? propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, containerProperty); - if (!reader.ReadForType(property.PropertyContract, propertyConverter != null)) - { - throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); - } + if (!reader.ReadForType(property.PropertyContract, propertyConverter != null)) + { + throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); + } - if (propertyConverter != null && propertyConverter.CanRead) - { - creatorPropertyContext.Value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, null); + if (propertyConverter != null && propertyConverter.CanRead) + { + creatorPropertyContext.Value = DeserializeConvertable(propertyConverter, reader, property.PropertyType!, null); + } + else + { + creatorPropertyContext.Value = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null); + } + + continue; } else { - creatorPropertyContext.Value = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null); + if (!reader.Read()) + { + throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName)); + } } - - continue; } else { @@ -2256,9 +2298,9 @@ private List ResolvePropertyAndCreatorValues(JsonObjectC return propertyValues; } - public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultCreator) + public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty? containerMember, JsonProperty? containerProperty, string? id, out bool createdFromNonDefaultCreator) { - object newObject = null; + object? newObject = null; if (objectContract.OverrideCreator != null) { @@ -2299,12 +2341,12 @@ public object CreateNewObject(JsonReader reader, JsonObjectContract objectContra return newObject; } - private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id) + private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty? member, string? id) { OnDeserializing(reader, contract, newObject); // only need to keep a track of properties' presence if they are required or a value should be defaulted if missing - Dictionary propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate)) + Dictionary? propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate)) ? contract.Properties.ToDictionary(m => m, m => PropertyPresence.None) : null; @@ -2322,7 +2364,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon { case JsonToken.PropertyName: { - string propertyName = reader.Value.ToString(); + string propertyName = reader.Value!.ToString()!; if (CheckPropertyName(reader, propertyName)) { @@ -2333,7 +2375,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon { // attempt exact case match first // then try match ignoring case - JsonProperty property = contract.Properties.GetClosestMatchProperty(propertyName); + JsonProperty? property = contract.Properties.GetClosestMatchProperty(propertyName); if (property == null) { @@ -2373,7 +2415,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon property.PropertyContract = GetContractSafe(property.PropertyType); } - JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, member); + JsonConverter? propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, member); if (!reader.ReadForType(property.PropertyContract, propertyConverter != null)) { @@ -2467,13 +2509,13 @@ private bool CheckPropertyName(JsonReader reader, string memberName) return false; } - private void SetExtensionData(JsonObjectContract contract, JsonProperty member, JsonReader reader, string memberName, object o) + private void SetExtensionData(JsonObjectContract contract, JsonProperty? member, JsonReader reader, string memberName, object o) { if (contract.ExtensionDataSetter != null) { try { - object value = ReadExtensionDataValue(contract, member, reader); + object? value = ReadExtensionDataValue(contract, member, reader); contract.ExtensionDataSetter(o, memberName, value); } @@ -2488,9 +2530,9 @@ private void SetExtensionData(JsonObjectContract contract, JsonProperty member, } } - private object ReadExtensionDataValue(JsonObjectContract contract, JsonProperty member, JsonReader reader) + private object? ReadExtensionDataValue(JsonObjectContract contract, JsonProperty? member, JsonReader reader) { - object value; + object? value; if (contract.ExtensionDataIsJToken) { value = JToken.ReadFrom(reader); @@ -2527,7 +2569,7 @@ private void EndProcessProperty(object newObject, JsonReader reader, JsonObjectC if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && property.Writable) { - property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType)); + property.ValueProvider!.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract!, property.PropertyType)); } } break; @@ -2557,7 +2599,7 @@ private void EndProcessProperty(object newObject, JsonReader reader, JsonObjectC } } - private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dictionary requiredProperties) + private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dictionary? requiredProperties) { if (property != null && requiredProperties != null) { @@ -2565,7 +2607,7 @@ private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dicti switch (reader.TokenType) { case JsonToken.String: - propertyPresence = (CoerceEmptyStringToNull(property.PropertyType, property.PropertyContract, (string)reader.Value)) + propertyPresence = (CoerceEmptyStringToNull(property.PropertyType, property.PropertyContract, (string)reader.Value!)) ? PropertyPresence.Null : PropertyPresence.Value; break; diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs index 9ce79c69d..7feb6ad35 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs @@ -37,18 +37,19 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json.Utilities; using System.Runtime.Serialization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Newtonsoft.Json.Serialization { internal class JsonSerializerInternalWriter : JsonSerializerInternalBase { - private Type _rootType; + private Type? _rootType; private int _rootLevel; private readonly List _serializeStack = new List(); @@ -57,7 +58,7 @@ public JsonSerializerInternalWriter(JsonSerializer serializer) { } - public void Serialize(JsonWriter jsonWriter, object value, Type objectType) + public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType) { if (jsonWriter == null) { @@ -67,13 +68,13 @@ public void Serialize(JsonWriter jsonWriter, object value, Type objectType) _rootType = objectType; _rootLevel = _serializeStack.Count + 1; - JsonContract contract = GetContractSafe(value); + JsonContract? contract = GetContractSafe(value); try { if (ShouldWriteReference(value, null, contract, null, null)) { - WriteReference(jsonWriter, value); + WriteReference(jsonWriter, value!); } else { @@ -113,17 +114,22 @@ private JsonSerializerProxy GetInternalSerializer() return InternalSerializer; } - private JsonContract GetContractSafe(object value) + private JsonContract? GetContractSafe(object? value) { if (value == null) { return null; } + return GetContract(value); + } + + private JsonContract GetContract(object value) + { return Serializer._contractResolver.ResolveContract(value.GetType()); } - private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { if (contract.TypeCode == PrimitiveTypeCode.Bytes) { @@ -145,7 +151,7 @@ private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveCo JsonWriter.WriteValue(writer, contract.TypeCode, value); } - private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private void SerializeValue(JsonWriter writer, object? value, JsonContract? valueContract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { if (value == null) { @@ -153,7 +159,9 @@ private void SerializeValue(JsonWriter writer, object value, JsonContract valueC return; } - JsonConverter converter = + MiscellaneousUtils.Assert(valueContract != null); + + JsonConverter? converter = member?.Converter ?? containerProperty?.ItemConverter ?? containerContract?.ItemConverter ?? @@ -209,7 +217,7 @@ private void SerializeValue(JsonWriter writer, object value, JsonContract valueC } } - private bool? ResolveIsReference(JsonContract contract, JsonProperty property, JsonContainerContract collectionContract, JsonProperty containerProperty) + private bool? ResolveIsReference(JsonContract contract, JsonProperty? property, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { bool? isReference = null; @@ -237,12 +245,15 @@ private void SerializeValue(JsonWriter writer, object value, JsonContract valueC return isReference; } - private bool ShouldWriteReference(object value, JsonProperty property, JsonContract valueContract, JsonContainerContract collectionContract, JsonProperty containerProperty) + private bool ShouldWriteReference(object? value, JsonProperty? property, JsonContract? valueContract, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { if (value == null) { return false; } + + MiscellaneousUtils.Assert(valueContract != null); + if (valueContract.ContractType == JsonContractType.Primitive || valueContract.ContractType == JsonContractType.String) { return false; @@ -270,7 +281,7 @@ private bool ShouldWriteReference(object value, JsonProperty property, JsonContr return Serializer.GetReferenceResolver().IsReferenced(this, value); } - private bool ShouldWriteProperty(object memberValue, JsonObjectContract containerContract, JsonProperty property) + private bool ShouldWriteProperty(object? memberValue, JsonObjectContract? containerContract, JsonProperty property) { if (memberValue == null && ResolvedNullValueHandling(containerContract, property) == NullValueHandling.Ignore) { @@ -286,9 +297,16 @@ private bool ShouldWriteProperty(object memberValue, JsonObjectContract containe return true; } - private bool CheckForCircularReference(JsonWriter writer, object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty) + private bool CheckForCircularReference(JsonWriter writer, object? value, JsonProperty? property, JsonContract? contract, JsonContainerContract? containerContract, JsonProperty? containerProperty) { - if (value == null || contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String) + if (value == null) + { + return true; + } + + MiscellaneousUtils.Assert(contract != null); + + if (contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String) { return true; } @@ -376,12 +394,25 @@ private string GetReference(JsonWriter writer, object value) } } - internal static bool TryConvertToString(object value, Type type, out string s) + internal static bool TryConvertToString(object value, Type type, [NotNullWhen(true)]out string? s) { +#if HAVE_DATE_ONLY + if (value is DateOnly dateOnly) + { + s = dateOnly.ToString("yyyy'-'MM'-'dd", CultureInfo.InvariantCulture); + return true; + } + if (value is TimeOnly timeOnly) + { + s = timeOnly.ToString("HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture); + return true; + } +#endif + #if HAVE_TYPE_DESCRIPTOR if (JsonTypeReflector.CanTypeDescriptorConvertString(type, out TypeConverter converter)) { - s = converter.ConvertToInvariantString(value); + s = converter.ConvertToInvariantString(value)!; return true; } #endif @@ -394,10 +425,9 @@ internal static bool TryConvertToString(object value, Type type, out string s) } #endif - type = value as Type; - if (type != null) + if (value is Type t) { - s = type.AssemblyQualifiedName; + s = t.AssemblyQualifiedName!; return true; } @@ -409,7 +439,7 @@ private void SerializeString(JsonWriter writer, object value, JsonStringContract { OnSerializing(writer, contract, value); - TryConvertToString(value, contract.UnderlyingType, out string s); + TryConvertToString(value, contract.UnderlyingType, out string? s); writer.WriteValue(s); OnSerialized(writer, contract, value); @@ -435,7 +465,7 @@ private void OnSerialized(JsonWriter writer, JsonContract contract, object value contract.InvokeOnSerialized(value, Serializer._context); } - private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { OnSerializing(writer, contract, value); @@ -450,7 +480,7 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract JsonProperty property = contract.Properties[index]; try { - if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract memberContract, out object memberValue)) + if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract? memberContract, out object? memberValue)) { continue; } @@ -471,13 +501,13 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract } } - IEnumerable> extensionData = contract.ExtensionDataGetter?.Invoke(value); + IEnumerable>? extensionData = contract.ExtensionDataGetter?.Invoke(value); if (extensionData != null) { foreach (KeyValuePair e in extensionData) { - JsonContract keyContract = GetContractSafe(e.Key); - JsonContract valueContract = GetContractSafe(e.Value); + JsonContract keyContract = GetContract(e.Key); + JsonContract? valueContract = GetContractSafe(e.Value); string propertyName = GetPropertyName(writer, e.Key, keyContract, out _); @@ -488,7 +518,7 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract if (ShouldWriteReference(e.Value, null, valueContract, contract, member)) { writer.WritePropertyName(propertyName); - WriteReference(writer, e.Value); + WriteReference(writer, e.Value!); } else { @@ -511,16 +541,16 @@ private void SerializeObject(JsonWriter writer, object value, JsonObjectContract OnSerialized(writer, contract, value); } - private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, out JsonContract memberContract, out object memberValue) + private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContainerContract contract, JsonProperty? member, JsonProperty property, [NotNullWhen(true)]out JsonContract? memberContract, out object? memberValue) { if (!property.Ignored && property.Readable && ShouldSerialize(writer, property, value) && IsSpecified(writer, property, value)) { if (property.PropertyContract == null) { - property.PropertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType); + property.PropertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType!); } - memberValue = property.ValueProvider.GetValue(value); + memberValue = property.ValueProvider!.GetValue(value); memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : GetContractSafe(memberValue); if (ShouldWriteProperty(memberValue, contract as JsonObjectContract, property)) @@ -528,7 +558,7 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai if (ShouldWriteReference(memberValue, property, memberContract, contract, member)) { property.WritePropertyName(writer); - WriteReference(writer, memberValue); + WriteReference(writer, memberValue!); return false; } @@ -539,7 +569,7 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai if (memberValue == null) { - JsonObjectContract objectContract = contract as JsonObjectContract; + JsonObjectContract? objectContract = contract as JsonObjectContract; Required resolvedRequired = property._required ?? objectContract?.ItemRequired ?? Required.Default; if (resolvedRequired == Required.Always) { @@ -551,7 +581,9 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai } } +#pragma warning disable CS8762 // Parameter must have a non-null value when exiting in some condition. return true; +#pragma warning restore CS8762 // Parameter must have a non-null value when exiting in some condition. } } @@ -560,7 +592,7 @@ private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContai return false; } - private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { writer.WriteStartObject(); @@ -576,14 +608,14 @@ private void WriteObjectStart(JsonWriter writer, object value, JsonContract cont } } - private bool HasCreatorParameter(JsonContainerContract contract, JsonProperty property) + private bool HasCreatorParameter(JsonContainerContract? contract, JsonProperty property) { if (!(contract is JsonObjectContract objectContract)) { return false; } - return objectContract.CreatorParameters.Contains(property.PropertyName); + return objectContract.CreatorParameters.Contains(property.PropertyName!); } private void WriteReferenceIdProperty(JsonWriter writer, Type type, object value) @@ -627,7 +659,7 @@ private bool HasFlag(TypeNameHandling value, TypeNameHandling flag) return ((value & flag) == flag); } - private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { if (ShouldWriteReference(value, null, contract, collectionContract, containerProperty)) { @@ -658,7 +690,7 @@ private void SerializeConvertable(JsonWriter writer, JsonConverter converter, ob } } - private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { object underlyingList = values is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : values; @@ -678,7 +710,7 @@ private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContr { try { - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + JsonContract? valueContract = contract.FinalItemContract ?? GetContractSafe(value); if (ShouldWriteReference(value, null, valueContract, contract, member)) { @@ -721,7 +753,7 @@ private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContr OnSerialized(writer, contract, underlyingList); } - private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { OnSerializing(writer, contract, values); @@ -741,7 +773,7 @@ private void SerializeMultidimensionalArray(JsonWriter writer, Array values, Jso OnSerialized(writer, contract, values); } - private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, int initialDepth, int[] indices) + private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty? member, int initialDepth, int[] indices) { int dimension = indices.Length; int[] newIndices = new int[dimension + 1]; @@ -759,11 +791,11 @@ private void SerializeMultidimensionalArray(JsonWriter writer, Array values, Jso if (isTopLevel) { - object value = values.GetValue(newIndices); + object value = values.GetValue(newIndices)!; try { - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + JsonContract? valueContract = contract.FinalItemContract ?? GetContractSafe(value); if (ShouldWriteReference(value, null, valueContract, contract, member)) { @@ -798,7 +830,7 @@ private void SerializeMultidimensionalArray(JsonWriter writer, Array values, Jso writer.WriteEndArray(); } - private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { bool isReference = ResolveIsReference(contract, member, containerContract, containerProperty) ?? HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Arrays); // don't make readonly fields that aren't creator parameters the referenced value because they can't be deserialized to @@ -834,7 +866,7 @@ private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract #if HAVE_SECURITY_SAFE_CRITICAL_ATTRIBUTE [SecuritySafeCritical] #endif - private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { if (!JsonTypeReflector.FullyTrusted) { @@ -855,12 +887,12 @@ private void SerializeISerializable(JsonWriter writer, ISerializable value, Json foreach (SerializationEntry serializationEntry in serializationInfo) { - JsonContract valueContract = GetContractSafe(serializationEntry.Value); + JsonContract? valueContract = GetContractSafe(serializationEntry.Value); if (ShouldWriteReference(serializationEntry.Value, null, valueContract, contract, member)) { writer.WritePropertyName(serializationEntry.Name); - WriteReference(writer, serializationEntry.Value); + WriteReference(writer, serializationEntry.Value!); } else if (CheckForCircularReference(writer, serializationEntry.Value, null, valueContract, contract, member)) { @@ -877,7 +909,7 @@ private void SerializeISerializable(JsonWriter writer, ISerializable value, Json #endif #if HAVE_DYNAMIC - private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { OnSerializing(writer, contract, value); _serializeStack.Add(value); @@ -895,7 +927,7 @@ private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider valu { try { - if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract memberContract, out object memberValue)) + if (!CalculatePropertyValues(writer, value, contract, member, property, out JsonContract? memberContract, out object? memberValue)) { continue; } @@ -919,11 +951,11 @@ private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider valu foreach (string memberName in value.GetDynamicMemberNames()) { - if (contract.TryGetMember(value, memberName, out object memberValue)) + if (contract.TryGetMember(value, memberName, out object? memberValue)) { try { - JsonContract valueContract = GetContractSafe(memberValue); + JsonContract? valueContract = GetContractSafe(memberValue); if (!ShouldWriteDynamicProperty(memberValue)) { @@ -961,7 +993,7 @@ private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider valu } #endif - private bool ShouldWriteDynamicProperty(object memberValue) + private bool ShouldWriteDynamicProperty(object? memberValue) { if (Serializer._nullValueHandling == NullValueHandling.Ignore && memberValue == null) { @@ -977,7 +1009,7 @@ private bool ShouldWriteDynamicProperty(object memberValue) return true; } - private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) + private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty? member, JsonContainerContract? containerContract, JsonProperty? containerProperty) { TypeNameHandling resolvedTypeNameHandling = member?.TypeNameHandling @@ -995,7 +1027,7 @@ private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract { if (member != null) { - if (contract.NonNullableUnderlyingType != member.PropertyContract.CreatedType) + if (contract.NonNullableUnderlyingType != member.PropertyContract!.CreatedType) { return true; } @@ -1021,8 +1053,9 @@ private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract return false; } - private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) + private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty? member, JsonContainerContract? collectionContract, JsonProperty? containerProperty) { +#pragma warning disable CS8600, CS8602, CS8604 object underlyingDictionary = values is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : values; OnSerializing(writer, contract, underlyingDictionary); @@ -1059,7 +1092,7 @@ private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDict try { object value = entry.Value; - JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value); + JsonContract? valueContract = contract.FinalItemContract ?? GetContractSafe(value); if (ShouldWriteReference(value, null, valueContract, contract, member)) { @@ -1101,6 +1134,7 @@ private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDict _serializeStack.RemoveAt(_serializeStack.Count - 1); OnSerialized(writer, contract, underlyingDictionary); +#pragma warning restore CS8600, CS8602, CS8604 } private string GetPropertyName(JsonWriter writer, object name, JsonContract contract, out bool escape) @@ -1150,16 +1184,16 @@ private string GetPropertyName(JsonWriter writer, object name, JsonContract cont { escape = true; - if (primitiveContract.IsEnum && EnumUtils.TryToString(primitiveContract.NonNullableUnderlyingType, name, null, out string enumName)) + if (primitiveContract.IsEnum && EnumUtils.TryToString(primitiveContract.NonNullableUnderlyingType, name, null, out string? enumName)) { return enumName; } - return Convert.ToString(name, CultureInfo.InvariantCulture); + return Convert.ToString(name, CultureInfo.InvariantCulture)!; } } } - else if (TryConvertToString(name, name.GetType(), out string propertyName)) + else if (TryConvertToString(name, name.GetType(), out string? propertyName)) { escape = true; return propertyName; @@ -1167,7 +1201,7 @@ private string GetPropertyName(JsonWriter writer, object name, JsonContract cont else { escape = true; - return name.ToString(); + return name.ToString()!; } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs index a5ff8c052..a122fe001 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerProxy.cs @@ -34,29 +34,29 @@ namespace Newtonsoft.Json.Serialization { internal class JsonSerializerProxy : JsonSerializer { - private readonly JsonSerializerInternalReader _serializerReader; - private readonly JsonSerializerInternalWriter _serializerWriter; - private readonly JsonSerializer _serializer; + private readonly JsonSerializerInternalReader? _serializerReader; + private readonly JsonSerializerInternalWriter? _serializerWriter; + internal readonly JsonSerializer _serializer; - public override event EventHandler Error + public override event EventHandler? Error { add => _serializer.Error += value; remove => _serializer.Error -= value; } - public override IReferenceResolver ReferenceResolver + public override IReferenceResolver? ReferenceResolver { get => _serializer.ReferenceResolver; set => _serializer.ReferenceResolver = value; } - public override ITraceWriter TraceWriter + public override ITraceWriter? TraceWriter { get => _serializer.TraceWriter; set => _serializer.TraceWriter = value; } - public override IEqualityComparer EqualityComparer + public override IEqualityComparer? EqualityComparer { get => _serializer.EqualityComparer; set => _serializer.EqualityComparer = value; @@ -230,7 +230,7 @@ internal JsonSerializerInternalBase GetInternalSerializer() } else { - return _serializerWriter; + return _serializerWriter!; } } @@ -250,7 +250,7 @@ public JsonSerializerProxy(JsonSerializerInternalWriter serializerWriter) _serializer = serializerWriter.Serializer; } - internal override object DeserializeInternal(JsonReader reader, Type objectType) + internal override object? DeserializeInternal(JsonReader reader, Type? objectType) { if (_serializerReader != null) { @@ -274,7 +274,7 @@ internal override void PopulateInternal(JsonReader reader, object target) } } - internal override void SerializeInternal(JsonWriter jsonWriter, object value, Type rootType) + internal override void SerializeInternal(JsonWriter jsonWriter, object? value, Type? rootType) { if (_serializerWriter != null) { diff --git a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs index 25100201b..da8430071 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs @@ -33,6 +33,7 @@ using System.Security.Permissions; #endif using Newtonsoft.Json.Utilities; +using System.Runtime.CompilerServices; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -58,15 +59,15 @@ internal static class JsonTypeReflector public const string ConcurrentDictionaryTypeName = "System.Collections.Concurrent.ConcurrentDictionary`2"; - private static readonly ThreadSafeStore> CreatorCache = - new ThreadSafeStore>(GetCreator); + private static readonly ThreadSafeStore> CreatorCache = + new ThreadSafeStore>(GetCreator); #if !(NET20 || DOTNET) - private static readonly ThreadSafeStore AssociatedMetadataTypesCache = new ThreadSafeStore(GetAssociateMetadataTypeFromAttribute); - private static ReflectionObject _metadataTypeAttributeReflectionObject; + private static readonly ThreadSafeStore AssociatedMetadataTypesCache = new ThreadSafeStore(GetAssociateMetadataTypeFromAttribute); + private static ReflectionObject? _metadataTypeAttributeReflectionObject; #endif - public static T GetCachedAttribute(object attributeProvider) where T : Attribute + public static T? GetCachedAttribute(object attributeProvider) where T : Attribute { return CachedAttributeGetter.GetAttribute(attributeProvider); } @@ -96,14 +97,14 @@ public static bool CanTypeDescriptorConvertString(Type type, out TypeConverter t #endif #if HAVE_DATA_CONTRACTS - public static DataContractAttribute GetDataContractAttribute(Type type) + public static DataContractAttribute? GetDataContractAttribute(Type type) { // DataContractAttribute does not have inheritance - Type currentType = type; + Type? currentType = type; while (currentType != null) { - DataContractAttribute result = CachedAttributeGetter.GetAttribute(currentType); + DataContractAttribute? result = CachedAttributeGetter.GetAttribute(currentType); if (result != null) { return result; @@ -115,7 +116,7 @@ public static DataContractAttribute GetDataContractAttribute(Type type) return null; } - public static DataMemberAttribute GetDataMemberAttribute(MemberInfo memberInfo) + public static DataMemberAttribute? GetDataMemberAttribute(MemberInfo memberInfo) { // DataMemberAttribute does not have inheritance @@ -127,16 +128,16 @@ public static DataMemberAttribute GetDataMemberAttribute(MemberInfo memberInfo) // search property and then search base properties if nothing is returned and the property is virtual PropertyInfo propertyInfo = (PropertyInfo)memberInfo; - DataMemberAttribute result = CachedAttributeGetter.GetAttribute(propertyInfo); + DataMemberAttribute? result = CachedAttributeGetter.GetAttribute(propertyInfo); if (result == null) { if (propertyInfo.IsVirtual()) { - Type currentType = propertyInfo.DeclaringType; + Type? currentType = propertyInfo.DeclaringType; while (result == null && currentType != null) { - PropertyInfo baseProperty = (PropertyInfo)ReflectionUtils.GetMemberInfoFromType(currentType, propertyInfo); + PropertyInfo? baseProperty = (PropertyInfo?)ReflectionUtils.GetMemberInfoFromType(currentType, propertyInfo); if (baseProperty != null && baseProperty.IsVirtual()) { result = CachedAttributeGetter.GetAttribute(baseProperty); @@ -153,14 +154,14 @@ public static DataMemberAttribute GetDataMemberAttribute(MemberInfo memberInfo) public static MemberSerialization GetObjectMemberSerialization(Type objectType, bool ignoreSerializableAttribute) { - JsonObjectAttribute objectAttribute = GetCachedAttribute(objectType); + JsonObjectAttribute? objectAttribute = GetCachedAttribute(objectType); if (objectAttribute != null) { return objectAttribute.MemberSerialization; } #if HAVE_DATA_CONTRACTS - DataContractAttribute dataContractAttribute = GetDataContractAttribute(objectType); + DataContractAttribute? dataContractAttribute = GetDataContractAttribute(objectType); if (dataContractAttribute != null) { return MemberSerialization.OptIn; @@ -178,13 +179,13 @@ public static MemberSerialization GetObjectMemberSerialization(Type objectType, return MemberSerialization.OptOut; } - public static JsonConverter GetJsonConverter(object attributeProvider) + public static JsonConverter? GetJsonConverter(object attributeProvider) { - JsonConverterAttribute converterAttribute = GetCachedAttribute(attributeProvider); + JsonConverterAttribute? converterAttribute = GetCachedAttribute(attributeProvider); if (converterAttribute != null) { - Func creator = CreatorCache.Get(converterAttribute.ConverterType); + Func creator = CreatorCache.Get(converterAttribute.ConverterType); if (creator != null) { return (JsonConverter)creator(converterAttribute.ConverterParameters); @@ -200,19 +201,19 @@ public static JsonConverter GetJsonConverter(object attributeProvider) /// The type to create. /// Optional arguments to pass to an initializing constructor of the JsonConverter. /// If null, the default constructor is used. - public static JsonConverter CreateJsonConverterInstance(Type converterType, object[] args) + public static JsonConverter CreateJsonConverterInstance(Type converterType, object[]? args) { - Func converterCreator = CreatorCache.Get(converterType); + Func converterCreator = CreatorCache.Get(converterType); return (JsonConverter)converterCreator(args); } - public static NamingStrategy CreateNamingStrategyInstance(Type namingStrategyType, object[] args) + public static NamingStrategy CreateNamingStrategyInstance(Type namingStrategyType, object[]? args) { - Func converterCreator = CreatorCache.Get(namingStrategyType); + Func converterCreator = CreatorCache.Get(namingStrategyType); return (NamingStrategy)converterCreator(args); } - public static NamingStrategy GetContainerNamingStrategy(JsonContainerAttribute containerAttribute) + public static NamingStrategy? GetContainerNamingStrategy(JsonContainerAttribute containerAttribute) { if (containerAttribute.NamingStrategyInstance == null) { @@ -227,9 +228,9 @@ public static NamingStrategy GetContainerNamingStrategy(JsonContainerAttribute c return containerAttribute.NamingStrategyInstance; } - private static Func GetCreator(Type type) + private static Func GetCreator(Type type) { - Func defaultConstructor = (ReflectionUtils.HasDefaultConstructor(type, false)) + Func? defaultConstructor = (ReflectionUtils.HasDefaultConstructor(type, false)) ? ReflectionDelegateFactory.CreateDefaultConstructor(type) : null; @@ -248,7 +249,7 @@ private static Func GetCreator(Type type) return param.GetType(); }).ToArray(); - ConstructorInfo parameterizedConstructorInfo = type.GetConstructor(paramTypes); + ConstructorInfo? parameterizedConstructorInfo = type.GetConstructor(paramTypes); if (parameterizedConstructorInfo != null) { @@ -276,12 +277,12 @@ private static Func GetCreator(Type type) } #if !(NET20 || DOTNET) - private static Type GetAssociatedMetadataType(Type type) + private static Type? GetAssociatedMetadataType(Type type) { return AssociatedMetadataTypesCache.Get(type); } - private static Type GetAssociateMetadataTypeFromAttribute(Type type) + private static Type? GetAssociateMetadataTypeFromAttribute(Type type) { Attribute[] customAttributes = ReflectionUtils.GetAttributes(type, null, true); @@ -300,7 +301,7 @@ private static Type GetAssociateMetadataTypeFromAttribute(Type type) _metadataTypeAttributeReflectionObject = ReflectionObject.Create(attributeType, metadataClassTypeName); } - return (Type)_metadataTypeAttributeReflectionObject.GetValue(attribute, metadataClassTypeName); + return (Type?)_metadataTypeAttributeReflectionObject.GetValue(attribute, metadataClassTypeName); } } @@ -308,12 +309,12 @@ private static Type GetAssociateMetadataTypeFromAttribute(Type type) } #endif - private static T GetAttribute(Type type) where T : Attribute + private static T? GetAttribute(Type type) where T : Attribute { - T attribute; + T? attribute; #if !(NET20 || DOTNET) - Type metadataType = GetAssociatedMetadataType(type); + Type? metadataType = GetAssociatedMetadataType(type); if (metadataType != null) { attribute = ReflectionUtils.GetAttribute(metadataType, true); @@ -342,15 +343,15 @@ private static T GetAttribute(Type type) where T : Attribute return null; } - private static T GetAttribute(MemberInfo memberInfo) where T : Attribute + private static T? GetAttribute(MemberInfo memberInfo) where T : Attribute { - T attribute; + T? attribute; #if !(NET20 || DOTNET) - Type metadataType = GetAssociatedMetadataType(memberInfo.DeclaringType); + Type? metadataType = GetAssociatedMetadataType(memberInfo.DeclaringType!); if (metadataType != null) { - MemberInfo metadataTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(metadataType, memberInfo); + MemberInfo? metadataTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(metadataType, memberInfo); if (metadataTypeMemberInfo != null) { @@ -373,7 +374,7 @@ private static T GetAttribute(MemberInfo memberInfo) where T : Attribute { foreach (Type typeInterface in memberInfo.DeclaringType.GetInterfaces()) { - MemberInfo interfaceTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(typeInterface, memberInfo); + MemberInfo? interfaceTypeMemberInfo = ReflectionUtils.GetMemberInfoFromType(typeInterface, memberInfo); if (interfaceTypeMemberInfo != null) { @@ -423,7 +424,7 @@ public static bool IsSerializable(object provider) } #endif - public static T GetAttribute(object provider) where T : Attribute + public static T? GetAttribute(object provider) where T : Attribute { if (provider is Type type) { @@ -459,7 +460,9 @@ public static bool DynamicCodeGeneration { if (_dynamicCodeGeneration == null) { -#if HAVE_CAS +#if HAVE_DYNAMIC_CODE_COMPILED + _dynamicCodeGeneration = RuntimeFeature.IsDynamicCodeCompiled; +#elif HAVE_CAS try { new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand(); diff --git a/Src/Newtonsoft.Json/Serialization/KebabCaseNamingStrategy.cs b/Src/Newtonsoft.Json/Serialization/KebabCaseNamingStrategy.cs new file mode 100644 index 000000000..16ac282b7 --- /dev/null +++ b/Src/Newtonsoft.Json/Serialization/KebabCaseNamingStrategy.cs @@ -0,0 +1,84 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using Newtonsoft.Json.Utilities; + +namespace Newtonsoft.Json.Serialization +{ + /// + /// A kebab case naming strategy. + /// + public class KebabCaseNamingStrategy : NamingStrategy + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A flag indicating whether dictionary keys should be processed. + /// + /// + /// A flag indicating whether explicitly specified property names should be processed, + /// e.g. a property name customized with a . + /// + public KebabCaseNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames) + { + ProcessDictionaryKeys = processDictionaryKeys; + OverrideSpecifiedNames = overrideSpecifiedNames; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A flag indicating whether dictionary keys should be processed. + /// + /// + /// A flag indicating whether explicitly specified property names should be processed, + /// e.g. a property name customized with a . + /// + /// + /// A flag indicating whether extension data names should be processed. + /// + public KebabCaseNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) + : this(processDictionaryKeys, overrideSpecifiedNames) + { + ProcessExtensionDataNames = processExtensionDataNames; + } + + /// + /// Initializes a new instance of the class. + /// + public KebabCaseNamingStrategy() + { + } + + /// + /// Resolves the specified property name. + /// + /// The property name to resolve. + /// The resolved property name. + protected override string ResolvePropertyName(string name) => StringUtils.ToKebabCase(name); + } +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs b/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs index 6816b6568..a2672ed20 100644 --- a/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/MemoryTraceWriter.cs @@ -41,7 +41,7 @@ public MemoryTraceWriter() /// The at which to write this trace. /// The trace message. /// The trace exception. This parameter is optional. - public void Trace(TraceLevel level, string message, Exception ex) + public void Trace(TraceLevel level, string message, Exception? ex) { StringBuilder sb = new StringBuilder(); sb.Append(DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", CultureInfo.InvariantCulture)); diff --git a/Src/Newtonsoft.Json/Serialization/NamingStrategy.cs b/Src/Newtonsoft.Json/Serialization/NamingStrategy.cs index 461bad93e..7412531e9 100644 --- a/Src/Newtonsoft.Json/Serialization/NamingStrategy.cs +++ b/Src/Newtonsoft.Json/Serialization/NamingStrategy.cs @@ -123,14 +123,14 @@ public override int GetHashCode() /// /// /// - public override bool Equals(object obj) => Equals(obj as NamingStrategy); + public override bool Equals(object? obj) => Equals(obj as NamingStrategy); /// /// Compare to another NamingStrategy /// /// /// - protected bool Equals(NamingStrategy other) + protected bool Equals(NamingStrategy? other) { if (other == null) { diff --git a/Src/Newtonsoft.Json/Serialization/ObjectConstructor.cs b/Src/Newtonsoft.Json/Serialization/ObjectConstructor.cs index 380674fe1..a6945e747 100644 --- a/Src/Newtonsoft.Json/Serialization/ObjectConstructor.cs +++ b/Src/Newtonsoft.Json/Serialization/ObjectConstructor.cs @@ -29,5 +29,5 @@ namespace Newtonsoft.Json.Serialization /// Represents a method that constructs an object. /// /// The object type to create. - public delegate object ObjectConstructor(params object[] args); + public delegate object ObjectConstructor(params object?[] args); } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Serialization/ReflectionValueProvider.cs b/Src/Newtonsoft.Json/Serialization/ReflectionValueProvider.cs index 9c3a657ae..7ad281b56 100644 --- a/Src/Newtonsoft.Json/Serialization/ReflectionValueProvider.cs +++ b/Src/Newtonsoft.Json/Serialization/ReflectionValueProvider.cs @@ -52,7 +52,7 @@ public ReflectionValueProvider(MemberInfo memberInfo) /// /// The target to set the value on. /// The value to set on the target. - public void SetValue(object target, object value) + public void SetValue(object target, object? value) { try { @@ -69,7 +69,7 @@ public void SetValue(object target, object value) /// /// The target to get the value from. /// The value. - public object GetValue(object target) + public object? GetValue(object target) { try { diff --git a/Src/Newtonsoft.Json/Serialization/SerializationBinderAdapter.cs b/Src/Newtonsoft.Json/Serialization/SerializationBinderAdapter.cs index 033692c49..e5465af80 100644 --- a/Src/Newtonsoft.Json/Serialization/SerializationBinderAdapter.cs +++ b/Src/Newtonsoft.Json/Serialization/SerializationBinderAdapter.cs @@ -41,12 +41,12 @@ public SerializationBinderAdapter(SerializationBinder serializationBinder) } #pragma warning restore 618 - public Type BindToType(string assemblyName, string typeName) + public Type BindToType(string? assemblyName, string typeName) { - return SerializationBinder.BindToType(assemblyName, typeName); + return SerializationBinder.BindToType(assemblyName!, typeName)!; } - public void BindToName(Type serializedType, out string assemblyName, out string typeName) + public void BindToName(Type serializedType, out string? assemblyName, out string? typeName) { #if HAVE_SERIALIZATION_BINDER_BIND_TO_NAME SerializationBinder.BindToName(serializedType, out assemblyName, out typeName); diff --git a/Src/Newtonsoft.Json/Serialization/TraceJsonReader.cs b/Src/Newtonsoft.Json/Serialization/TraceJsonReader.cs index 5dbbd5de7..53ab49777 100644 --- a/Src/Newtonsoft.Json/Serialization/TraceJsonReader.cs +++ b/Src/Newtonsoft.Json/Serialization/TraceJsonReader.cs @@ -68,16 +68,16 @@ public override bool Read() return value; } - public override string ReadAsString() + public override string? ReadAsString() { - string value = _innerReader.ReadAsString(); + string? value = _innerReader.ReadAsString(); WriteCurrentToken(); return value; } - public override byte[] ReadAsBytes() + public override byte[]? ReadAsBytes() { - byte[] value = _innerReader.ReadAsBytes(); + byte[]? value = _innerReader.ReadAsBytes(); WriteCurrentToken(); return value; } @@ -136,9 +136,9 @@ public override char QuoteChar public override JsonToken TokenType => _innerReader.TokenType; - public override object Value => _innerReader.Value; + public override object? Value => _innerReader.Value; - public override Type ValueType => _innerReader.ValueType; + public override Type? ValueType => _innerReader.ValueType; public override void Close() { diff --git a/Src/Newtonsoft.Json/Serialization/TraceJsonWriter.cs b/Src/Newtonsoft.Json/Serialization/TraceJsonWriter.cs index 95d9ebae2..b660b07f7 100644 --- a/Src/Newtonsoft.Json/Serialization/TraceJsonWriter.cs +++ b/Src/Newtonsoft.Json/Serialization/TraceJsonWriter.cs @@ -144,7 +144,7 @@ public override void WriteValue(char? value) } } - public override void WriteValue(byte[] value) + public override void WriteValue(byte[]? value) { _textWriter.WriteValue(value); _innerWriter.WriteValue(value); @@ -321,7 +321,7 @@ public override void WriteValue(long? value) } } - public override void WriteValue(object value) + public override void WriteValue(object? value) { #if HAVE_BIG_INTEGER if (value is BigInteger) @@ -389,7 +389,7 @@ public override void WriteValue(short? value) } } - public override void WriteValue(string value) + public override void WriteValue(string? value) { _textWriter.WriteValue(value); _innerWriter.WriteValue(value); @@ -459,7 +459,7 @@ public override void WriteValue(ulong? value) } } - public override void WriteValue(Uri value) + public override void WriteValue(Uri? value) { _textWriter.WriteValue(value); _innerWriter.WriteValue(value); @@ -501,7 +501,7 @@ public override void WriteWhitespace(string ws) base.WriteWhitespace(ws); } - public override void WriteComment(string text) + public override void WriteComment(string? text) { _textWriter.WriteComment(text); _innerWriter.WriteComment(text); @@ -566,7 +566,7 @@ public override void WriteEndObject() base.WriteEndObject(); } - public override void WriteRawValue(string json) + public override void WriteRawValue(string? json) { _textWriter.WriteRawValue(json); _innerWriter.WriteRawValue(json); @@ -575,7 +575,7 @@ public override void WriteRawValue(string json) InternalWriteValue(JsonToken.Undefined); } - public override void WriteRaw(string json) + public override void WriteRaw(string? json) { _textWriter.WriteRaw(json); _innerWriter.WriteRaw(json); diff --git a/Src/Newtonsoft.Json/SerializationBinder.cs b/Src/Newtonsoft.Json/SerializationBinder.cs index b3e480f08..9a6193c06 100644 --- a/Src/Newtonsoft.Json/SerializationBinder.cs +++ b/Src/Newtonsoft.Json/SerializationBinder.cs @@ -17,7 +17,7 @@ public abstract class SerializationBinder /// Specifies the name of the serialized object. /// Specifies the name of the serialized object /// The type of the object the formatter creates a new instance of. - public abstract Type BindToType(string assemblyName, string typeName); + public abstract Type BindToType(string? assemblyName, string typeName); /// /// When overridden in a derived class, controls the binding of a serialized object to a type. @@ -25,7 +25,7 @@ public abstract class SerializationBinder /// The type of the object the formatter creates a new instance of. /// Specifies the name of the serialized object. /// Specifies the name of the serialized object. - public virtual void BindToName(Type serializedType, out string assemblyName, out string typeName) + public virtual void BindToName(Type serializedType, out string? assemblyName, out string? typeName) { assemblyName = null; typeName = null; diff --git a/Src/Newtonsoft.Json/Utilities/AsyncUtils.cs b/Src/Newtonsoft.Json/Utilities/AsyncUtils.cs index 49cbad97e..578b37de7 100644 --- a/Src/Newtonsoft.Json/Utilities/AsyncUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/AsyncUtils.cs @@ -40,12 +40,12 @@ internal static class AsyncUtils internal static Task ToAsync(this bool value) => value ? True : False; - public static Task CancelIfRequestedAsync(this CancellationToken cancellationToken) + public static Task? CancelIfRequestedAsync(this CancellationToken cancellationToken) { return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : null; } - public static Task CancelIfRequestedAsync(this CancellationToken cancellationToken) + public static Task? CancelIfRequestedAsync(this CancellationToken cancellationToken) { return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : null; } @@ -54,14 +54,16 @@ public static Task CancelIfRequestedAsync(this CancellationToken cancellat // previous frameworks. public static Task FromCanceled(this CancellationToken cancellationToken) { - Debug.Assert(cancellationToken.IsCancellationRequested); + MiscellaneousUtils.Assert(cancellationToken.IsCancellationRequested); return new Task(() => {}, cancellationToken); } public static Task FromCanceled(this CancellationToken cancellationToken) { - Debug.Assert(cancellationToken.IsCancellationRequested); + MiscellaneousUtils.Assert(cancellationToken.IsCancellationRequested); +#pragma warning disable CS8603 // Possible null reference return. return new Task(() => default, cancellationToken); +#pragma warning restore CS8603 // Possible null reference return. } // Task.Delay(0) is optimised as a cached task within the framework, and indeed @@ -71,33 +73,33 @@ public static Task FromCanceled(this CancellationToken cancellationToken) public static Task WriteAsync(this TextWriter writer, char value, CancellationToken cancellationToken) { - Debug.Assert(writer != null); + MiscellaneousUtils.Assert(writer != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : writer.WriteAsync(value); } - public static Task WriteAsync(this TextWriter writer, string value, CancellationToken cancellationToken) + public static Task WriteAsync(this TextWriter writer, string? value, CancellationToken cancellationToken) { - Debug.Assert(writer != null); + MiscellaneousUtils.Assert(writer != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : writer.WriteAsync(value); } public static Task WriteAsync(this TextWriter writer, char[] value, int start, int count, CancellationToken cancellationToken) { - Debug.Assert(writer != null); + MiscellaneousUtils.Assert(writer != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : writer.WriteAsync(value, start, count); } public static Task ReadAsync(this TextReader reader, char[] buffer, int index, int count, CancellationToken cancellationToken) { - Debug.Assert(reader != null); + MiscellaneousUtils.Assert(reader != null); return cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : reader.ReadAsync(buffer, index, count); } - public static bool IsCompletedSucessfully(this Task task) + public static bool IsCompletedSuccessfully(this Task task) { // IsCompletedSucessfully is the faster method, but only currently exposed on .NET Core 2.0 -#if NETCOREAPP2_0 - return task.IsCompletedSucessfully; +#if NETCOREAPP2_0_OR_GREATER + return task.IsCompletedSuccessfully; #else return task.Status == TaskStatus.RanToCompletion; #endif diff --git a/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs b/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs index b65465eac..887ee7f0c 100644 --- a/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs +++ b/Src/Newtonsoft.Json/Utilities/Base64Encoder.cs @@ -40,7 +40,7 @@ internal class Base64Encoder private readonly char[] _charsLine = new char[Base64LineSize]; private readonly TextWriter _writer; - private byte[] _leftOverBytes; + private byte[]? _leftOverBytes; private int _leftOverBytesCount; public Base64Encoder(TextWriter writer) @@ -78,12 +78,12 @@ public void Encode(byte[] buffer, int index, int count) if (_leftOverBytesCount > 0) { - if(FulfillFromLeftover(buffer, index, ref count)) + if (FulfillFromLeftover(buffer, index, ref count)) { return; } - int num2 = Convert.ToBase64CharArray(_leftOverBytes, 0, 3, _charsLine, 0); + int num2 = Convert.ToBase64CharArray(_leftOverBytes!, 0, 3, _charsLine, 0); WriteChars(_charsLine, 0, num2); } @@ -128,7 +128,7 @@ private bool FulfillFromLeftover(byte[] buffer, int index, ref int count) int leftOverBytesCount = _leftOverBytesCount; while (leftOverBytesCount < 3 && count > 0) { - _leftOverBytes[leftOverBytesCount++] = buffer[index++]; + _leftOverBytes![leftOverBytesCount++] = buffer[index++]; count--; } @@ -145,7 +145,7 @@ public void Flush() { if (_leftOverBytesCount > 0) { - int count = Convert.ToBase64CharArray(_leftOverBytes, 0, _leftOverBytesCount, _charsLine, 0); + int count = Convert.ToBase64CharArray(_leftOverBytes!, 0, _leftOverBytesCount, _charsLine, 0); WriteChars(_charsLine, 0, count); _leftOverBytesCount = 0; } @@ -169,7 +169,7 @@ public async Task EncodeAsync(byte[] buffer, int index, int count, CancellationT return; } - int num2 = Convert.ToBase64CharArray(_leftOverBytes, 0, 3, _charsLine, 0); + int num2 = Convert.ToBase64CharArray(_leftOverBytes!, 0, 3, _charsLine, 0); await WriteCharsAsync(_charsLine, 0, num2, cancellationToken).ConfigureAwait(false); } @@ -203,7 +203,7 @@ public Task FlushAsync(CancellationToken cancellationToken) if (_leftOverBytesCount > 0) { - int count = Convert.ToBase64CharArray(_leftOverBytes, 0, _leftOverBytesCount, _charsLine, 0); + int count = Convert.ToBase64CharArray(_leftOverBytes!, 0, _leftOverBytesCount, _charsLine, 0); _leftOverBytesCount = 0; return WriteCharsAsync(_charsLine, 0, count, cancellationToken); } diff --git a/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs b/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs index 3ee3c5969..7ed826d36 100644 --- a/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs +++ b/Src/Newtonsoft.Json/Utilities/BidirectionalDictionary.cs @@ -25,11 +25,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace Newtonsoft.Json.Utilities { internal class BidirectionalDictionary + where TFirst : notnull + where TSecond : notnull { private readonly IDictionary _firstToSecond; private readonly IDictionary _secondToFirst; @@ -61,17 +64,17 @@ public BidirectionalDictionary(IEqualityComparer firstEqualityComparer, public void Set(TFirst first, TSecond second) { - if (_firstToSecond.TryGetValue(first, out TSecond existingSecond)) + if (_firstToSecond.TryGetValue(first, out TSecond? existingSecond)) { - if (!existingSecond.Equals(second)) + if (!existingSecond!.Equals(second)) { throw new ArgumentException(_duplicateFirstErrorMessage.FormatWith(CultureInfo.InvariantCulture, first)); } } - if (_secondToFirst.TryGetValue(second, out TFirst existingFirst)) + if (_secondToFirst.TryGetValue(second, out TFirst? existingFirst)) { - if (!existingFirst.Equals(first)) + if (!existingFirst!.Equals(first)) { throw new ArgumentException(_duplicateSecondErrorMessage.FormatWith(CultureInfo.InvariantCulture, second)); } @@ -81,12 +84,12 @@ public void Set(TFirst first, TSecond second) _secondToFirst.Add(second, first); } - public bool TryGetByFirst(TFirst first, out TSecond second) + public bool TryGetByFirst(TFirst first, [NotNullWhen(true)] out TSecond? second) { return _firstToSecond.TryGetValue(first, out second); } - public bool TryGetBySecond(TSecond second, out TFirst first) + public bool TryGetBySecond(TSecond second, [NotNullWhen(true)] out TFirst? first) { return _secondToFirst.TryGetValue(second, out first); } diff --git a/Src/Newtonsoft.Json/Utilities/BoxedPrimitives.cs b/Src/Newtonsoft.Json/Utilities/BoxedPrimitives.cs new file mode 100644 index 000000000..e6fb4f2de --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/BoxedPrimitives.cs @@ -0,0 +1,116 @@ +#region License +// Copyright (c) 2022 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +namespace Newtonsoft.Json.Utilities +{ + internal static class BoxedPrimitives + { + internal static object Get(bool value) => value ? BooleanTrue : BooleanFalse; + + internal static readonly object BooleanTrue = true; + internal static readonly object BooleanFalse = false; + + internal static object Get(int value) => value switch + { + -1 => Int32_M1, + 0 => Int32_0, + 1 => Int32_1, + 2 => Int32_2, + 3 => Int32_3, + 4 => Int32_4, + 5 => Int32_5, + 6 => Int32_6, + 7 => Int32_7, + 8 => Int32_8, + _ => value, + }; + + // integers tend to be weighted towards a handful of low numbers; we could argue + // for days over the "correct" range to have special handling, but I'm arbitrarily + // mirroring the same decision as the IL opcodes, which has M1 thru 8 + internal static readonly object Int32_M1 = -1; + internal static readonly object Int32_0 = 0; + internal static readonly object Int32_1 = 1; + internal static readonly object Int32_2 = 2; + internal static readonly object Int32_3 = 3; + internal static readonly object Int32_4 = 4; + internal static readonly object Int32_5 = 5; + internal static readonly object Int32_6 = 6; + internal static readonly object Int32_7 = 7; + internal static readonly object Int32_8 = 8; + + internal static object Get(long value) => value switch + { + -1 => Int64_M1, + 0 => Int64_0, + 1 => Int64_1, + 2 => Int64_2, + 3 => Int64_3, + 4 => Int64_4, + 5 => Int64_5, + 6 => Int64_6, + 7 => Int64_7, + 8 => Int64_8, + _ => value, + }; + + internal static readonly object Int64_M1 = -1L; + internal static readonly object Int64_0 = 0L; + internal static readonly object Int64_1 = 1L; + internal static readonly object Int64_2 = 2L; + internal static readonly object Int64_3 = 3L; + internal static readonly object Int64_4 = 4L; + internal static readonly object Int64_5 = 5L; + internal static readonly object Int64_6 = 6L; + internal static readonly object Int64_7 = 7L; + internal static readonly object Int64_8 = 8L; + + internal static object Get(decimal value) => value == decimal.Zero ? DecimalZero : value; + + private static readonly object DecimalZero = decimal.Zero; + + internal static object Get(double value) + { + if (value == 0.0d) + { + return DoubleZero; + } + if (double.IsInfinity(value)) + { + return double.IsPositiveInfinity(value) ? DoublePositiveInfinity : DoubleNegativeInfinity; + } + if (double.IsNaN(value)) + { + return DoubleNaN; + } + return value; + } + + internal static readonly object DoubleNaN = double.NaN; + internal static readonly object DoublePositiveInfinity = double.PositiveInfinity; + internal static readonly object DoubleNegativeInfinity = double.NegativeInfinity; + internal static readonly object DoubleZero = (double)0; + } +} diff --git a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs index 59694ac09..8b0a0125d 100644 --- a/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/CollectionUtils.cs @@ -116,17 +116,17 @@ public static bool IsDictionaryType(Type type) return false; } - public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType) + public static ConstructorInfo? ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType) { Type genericConstructorArgument = typeof(IList<>).MakeGenericType(collectionItemType); return ResolveEnumerableCollectionConstructor(collectionType, collectionItemType, genericConstructorArgument); } - public static ConstructorInfo ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType, Type constructorArgumentType) + public static ConstructorInfo? ResolveEnumerableCollectionConstructor(Type collectionType, Type collectionItemType, Type constructorArgumentType) { Type genericEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionItemType); - ConstructorInfo match = null; + ConstructorInfo? match = null; foreach (ConstructorInfo constructor in collectionType.GetConstructors(BindingFlags.Public | BindingFlags.Instance)) { @@ -248,6 +248,7 @@ public static int IndexOfReference(this List list, T item) return i; } } + return -1; } @@ -288,7 +289,7 @@ private static IList GetDimensions(IList values, int dimensionsCount) break; } - object v = currentArray[0]; + object? v = currentArray[0]; if (v is IList list) { currentArray = list; @@ -340,11 +341,11 @@ private static object JaggedArrayGetValue(IList values, int[] indices) int index = indices[i]; if (i == indices.Length - 1) { - return currentList[index]; + return currentList[index]!; } else { - currentList = (IList)currentList[index]; + currentList = (IList)currentList[index]!; } } return currentList; @@ -365,27 +366,23 @@ public static Array ToMultidimensionalArray(IList values, Type type, int rank) return multidimensionalArray; } - // 4.6 has Array.Empty to return a cached empty array. Lacking that in other - // frameworks, Enumerable.Empty happens to be implemented as a cached empty - // array in all versions (in .NET Core the same instance as Array.Empty). - // This includes the internal Linq bridge for 2.0. - // Since this method is simple and only 11 bytes long in a release build it's - // pretty much guaranteed to be inlined, giving us fast access of that cached - // array. With 4.5 and up we use AggressiveInlining just to be sure, so it's - // effectively the same as calling Array.Empty even when not available. -#if HAVE_METHOD_IMPL_ATTRIBUTE - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif public static T[] ArrayEmpty() { - T[] array = Enumerable.Empty() as T[]; - Debug.Assert(array != null); - // Defensively guard against a version of Linq where Enumerable.Empty doesn't - // return an array, but throw in debug versions so a better strategy can be - // used if that ever happens. +#if !HAS_ARRAY_EMPTY + // Enumerable.Empty no longer returns an empty array in .NET Core 3.0 + return EmptyArrayContainer.Empty; +#else + return Array.Empty(); +#endif + } + +#if !HAS_ARRAY_EMPTY + private static class EmptyArrayContainer + { #pragma warning disable CA1825 // Avoid zero-length array allocations. - return array ?? new T[0]; + public static readonly T[] Empty = new T[0]; #pragma warning restore CA1825 // Avoid zero-length array allocations. } +#endif } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/CollectionWrapper.cs b/Src/Newtonsoft.Json/Utilities/CollectionWrapper.cs index a1696670f..482dad0cd 100644 --- a/Src/Newtonsoft.Json/Utilities/CollectionWrapper.cs +++ b/Src/Newtonsoft.Json/Utilities/CollectionWrapper.cs @@ -44,9 +44,9 @@ internal interface IWrappedCollection : IList internal class CollectionWrapper : ICollection, IWrappedCollection { - private readonly IList _list; - private readonly ICollection _genericCollection; - private object _syncRoot; + private readonly IList? _list; + private readonly ICollection? _genericCollection; + private object? _syncRoot; public CollectionWrapper(IList list) { @@ -77,7 +77,7 @@ public virtual void Add(T item) } else { - _list.Add(item); + _list!.Add(item); } } @@ -89,7 +89,7 @@ public virtual void Clear() } else { - _list.Clear(); + _list!.Clear(); } } @@ -101,7 +101,7 @@ public virtual bool Contains(T item) } else { - return _list.Contains(item); + return _list!.Contains(item); } } @@ -113,7 +113,7 @@ public virtual void CopyTo(T[] array, int arrayIndex) } else { - _list.CopyTo(array, arrayIndex); + _list!.CopyTo(array, arrayIndex); } } @@ -127,7 +127,7 @@ public virtual int Count } else { - return _list.Count; + return _list!.Count; } } } @@ -142,7 +142,7 @@ public virtual bool IsReadOnly } else { - return _list.IsReadOnly; + return _list!.IsReadOnly; } } } @@ -155,11 +155,11 @@ public virtual bool Remove(T item) } else { - bool contains = _list.Contains(item); + bool contains = _list!.Contains(item); if (contains) { - _list.Remove(item); + _list!.Remove(item); } return contains; @@ -168,33 +168,33 @@ public virtual bool Remove(T item) public virtual IEnumerator GetEnumerator() { - return (_genericCollection ?? _list.Cast()).GetEnumerator(); + return (_genericCollection ?? _list!.Cast()).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { - return ((IEnumerable)_genericCollection ?? _list).GetEnumerator(); + return ((IEnumerable)_genericCollection! ?? _list!).GetEnumerator(); } - int IList.Add(object value) + int IList.Add(object? value) { VerifyValueType(value); - Add((T)value); + Add((T)value!); return (Count - 1); } - bool IList.Contains(object value) + bool IList.Contains(object? value) { if (IsCompatibleObject(value)) { - return Contains((T)value); + return Contains((T)value!); } return false; } - int IList.IndexOf(object value) + int IList.IndexOf(object? value) { if (_genericCollection != null) { @@ -203,7 +203,7 @@ int IList.IndexOf(object value) if (IsCompatibleObject(value)) { - return _list.IndexOf((T)value); + return _list!.IndexOf((T)value!); } return -1; @@ -216,10 +216,10 @@ void IList.RemoveAt(int index) throw new InvalidOperationException("Wrapped ICollection does not support RemoveAt."); } - _list.RemoveAt(index); + _list!.RemoveAt(index); } - void IList.Insert(int index, object value) + void IList.Insert(int index, object? value) { if (_genericCollection != null) { @@ -227,7 +227,7 @@ void IList.Insert(int index, object value) } VerifyValueType(value); - _list.Insert(index, (T)value); + _list!.Insert(index, (T)value!); } bool IList.IsFixedSize @@ -241,20 +241,20 @@ bool IList.IsFixedSize } else { - return _list.IsFixedSize; + return _list!.IsFixedSize; } } } - void IList.Remove(object value) + void IList.Remove(object? value) { if (IsCompatibleObject(value)) { - Remove((T)value); + Remove((T)value!); } } - object IList.this[int index] + object? IList.this[int index] { get { @@ -263,7 +263,7 @@ object IList.this[int index] throw new InvalidOperationException("Wrapped ICollection does not support indexer."); } - return _list[index]; + return _list![index]; } set { @@ -273,7 +273,7 @@ object IList.this[int index] } VerifyValueType(value); - _list[index] = (T)value; + _list![index] = (T?)value; } } @@ -297,7 +297,7 @@ object ICollection.SyncRoot } } - private static void VerifyValueType(object value) + private static void VerifyValueType(object? value) { if (!IsCompatibleObject(value)) { @@ -305,7 +305,7 @@ private static void VerifyValueType(object value) } } - private static bool IsCompatibleObject(object value) + private static bool IsCompatibleObject(object? value) { if (!(value is T) && (value != null || (typeof(T).IsValueType() && !ReflectionUtils.IsNullableType(typeof(T))))) { @@ -315,6 +315,6 @@ private static bool IsCompatibleObject(object value) return true; } - public object UnderlyingCollection => (object)_genericCollection ?? _list; + public object UnderlyingCollection => (object)_genericCollection! ?? _list!; } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs index f00d89478..b6837eca9 100644 --- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs @@ -27,6 +27,7 @@ using System.Collections.Generic; using System.Globalization; using System.ComponentModel; +using System.Runtime.CompilerServices; #if HAVE_BIG_INTEGER using System.Numerics; #endif @@ -36,6 +37,7 @@ #endif using Newtonsoft.Json.Serialization; using System.Reflection; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #endif @@ -94,8 +96,14 @@ internal enum PrimitiveTypeCode internal class TypeInformation { - public Type Type { get; set; } - public PrimitiveTypeCode TypeCode { get; set; } + public Type Type { get; } + public PrimitiveTypeCode TypeCode { get; } + + public TypeInformation(Type type, PrimitiveTypeCode typeCode) + { + Type = type; + TypeCode = typeCode; + } } internal enum ParseResult @@ -163,25 +171,25 @@ internal static class ConvertUtils private static readonly TypeInformation[] PrimitiveTypeCodes = { // need all of these. lookup against the index with TypeCode value - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Object }, - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.DBNull }, - new TypeInformation { Type = typeof(bool), TypeCode = PrimitiveTypeCode.Boolean }, - new TypeInformation { Type = typeof(char), TypeCode = PrimitiveTypeCode.Char }, - new TypeInformation { Type = typeof(sbyte), TypeCode = PrimitiveTypeCode.SByte }, - new TypeInformation { Type = typeof(byte), TypeCode = PrimitiveTypeCode.Byte }, - new TypeInformation { Type = typeof(short), TypeCode = PrimitiveTypeCode.Int16 }, - new TypeInformation { Type = typeof(ushort), TypeCode = PrimitiveTypeCode.UInt16 }, - new TypeInformation { Type = typeof(int), TypeCode = PrimitiveTypeCode.Int32 }, - new TypeInformation { Type = typeof(uint), TypeCode = PrimitiveTypeCode.UInt32 }, - new TypeInformation { Type = typeof(long), TypeCode = PrimitiveTypeCode.Int64 }, - new TypeInformation { Type = typeof(ulong), TypeCode = PrimitiveTypeCode.UInt64 }, - new TypeInformation { Type = typeof(float), TypeCode = PrimitiveTypeCode.Single }, - new TypeInformation { Type = typeof(double), TypeCode = PrimitiveTypeCode.Double }, - new TypeInformation { Type = typeof(decimal), TypeCode = PrimitiveTypeCode.Decimal }, - new TypeInformation { Type = typeof(DateTime), TypeCode = PrimitiveTypeCode.DateTime }, - new TypeInformation { Type = typeof(object), TypeCode = PrimitiveTypeCode.Empty }, // no 17 in TypeCode for some reason - new TypeInformation { Type = typeof(string), TypeCode = PrimitiveTypeCode.String } + new TypeInformation(typeof(object), PrimitiveTypeCode.Empty), + new TypeInformation(typeof(object), PrimitiveTypeCode.Object), + new TypeInformation(typeof(object), PrimitiveTypeCode.DBNull), + new TypeInformation(typeof(bool), PrimitiveTypeCode.Boolean), + new TypeInformation(typeof(char), PrimitiveTypeCode.Char), + new TypeInformation(typeof(sbyte), PrimitiveTypeCode.SByte), + new TypeInformation(typeof(byte), PrimitiveTypeCode.Byte), + new TypeInformation(typeof(short), PrimitiveTypeCode.Int16), + new TypeInformation(typeof(ushort), PrimitiveTypeCode.UInt16), + new TypeInformation(typeof(int), PrimitiveTypeCode.Int32), + new TypeInformation(typeof(uint), PrimitiveTypeCode.UInt32), + new TypeInformation(typeof(long), PrimitiveTypeCode.Int64), + new TypeInformation(typeof(ulong), PrimitiveTypeCode.UInt64), + new TypeInformation(typeof(float), PrimitiveTypeCode.Single), + new TypeInformation(typeof(double), PrimitiveTypeCode.Double), + new TypeInformation(typeof(decimal), PrimitiveTypeCode.Decimal), + new TypeInformation(typeof(DateTime), PrimitiveTypeCode.DateTime), + new TypeInformation(typeof(object), PrimitiveTypeCode.Empty), // no 17 in TypeCode for some reason + new TypeInformation(typeof(string), PrimitiveTypeCode.String) }; #endif @@ -207,7 +215,7 @@ public static PrimitiveTypeCode GetTypeCode(Type t, out bool isEnum) // performance? if (ReflectionUtils.IsNullableType(t)) { - Type nonNullable = Nullable.GetUnderlyingType(t); + Type nonNullable = Nullable.GetUnderlyingType(t)!; if (nonNullable.IsEnum()) { Type nullableUnderlyingType = typeof(Nullable<>).MakeGenericType(Enum.GetUnderlyingType(nonNullable)); @@ -248,14 +256,14 @@ public static TimeSpan ParseTimeSpan(string input) #endif } - private static readonly ThreadSafeStore, Func> CastConverters = - new ThreadSafeStore, Func>(CreateCastConverter); + private static readonly ThreadSafeStore, Func?> CastConverters = + new ThreadSafeStore, Func?>(CreateCastConverter); - private static Func CreateCastConverter(StructMultiKey t) + private static Func? CreateCastConverter(StructMultiKey t) { Type initialType = t.Value1; Type targetType = t.Value2; - MethodInfo castMethodInfo = targetType.GetMethod("op_Implicit", new[] { initialType }) + MethodInfo? castMethodInfo = targetType.GetMethod("op_Implicit", new[] { initialType }) ?? targetType.GetMethod("op_Explicit", new[] { initialType }); if (castMethodInfo == null) @@ -263,7 +271,7 @@ private static Func CreateCastConverter(StructMultiKey call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(castMethodInfo); + MethodCall call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(castMethodInfo); return o => call(null, o); } @@ -363,10 +371,10 @@ internal enum ConvertResult public static object Convert(object initialValue, CultureInfo culture, Type targetType) { - switch (TryConvertInternal(initialValue, culture, targetType, out object value)) + switch (TryConvertInternal(initialValue, culture, targetType, out object? value)) { case ConvertResult.Success: - return value; + return value!; case ConvertResult.CannotConvertNull: throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType)); case ConvertResult.NotInstantiableType: @@ -378,7 +386,7 @@ public static object Convert(object initialValue, CultureInfo culture, Type targ } } - private static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object value) + private static bool TryConvert(object? initialValue, CultureInfo culture, Type targetType, out object? value) { try { @@ -397,7 +405,7 @@ private static bool TryConvert(object initialValue, CultureInfo culture, Type ta } } - private static ConvertResult TryConvertInternal(object initialValue, CultureInfo culture, Type targetType, out object value) + private static ConvertResult TryConvertInternal(object? initialValue, CultureInfo culture, Type targetType, out object? value) { if (initialValue == null) { @@ -406,7 +414,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo if (ReflectionUtils.IsNullableType(targetType)) { - targetType = Nullable.GetUnderlyingType(targetType); + targetType = Nullable.GetUnderlyingType(targetType)!; } Type initialType = initialValue.GetType(); @@ -424,7 +432,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo { if (initialValue is string) { - value = Enum.Parse(targetType, initialValue.ToString(), true); + value = Enum.Parse(targetType, initialValue.ToString()!, true); return ConvertResult.Success; } else if (IsInteger(initialValue)) @@ -482,7 +490,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo } if (targetType == typeof(Version)) { - if (VersionTryParse(s, out Version result)) + if (VersionTryParse(s, out Version? result)) { value = result; return ConvertResult.Success; @@ -495,6 +503,18 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo value = Type.GetType(s, true); return ConvertResult.Success; } +#if HAVE_DATE_ONLY + if (targetType == typeof(DateOnly)) + { + value = DateOnly.ParseExact(s, "yyyy'-'MM'-'dd", CultureInfo.InvariantCulture); + return ConvertResult.Success; + } + if (targetType == typeof(TimeOnly)) + { + value = TimeOnly.ParseExact(s, "HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture); + return ConvertResult.Success; + } +#endif } #if HAVE_BIG_INTEGER @@ -567,7 +587,7 @@ private static ConvertResult TryConvertInternal(object initialValue, CultureInfo /// The converted type. If conversion was unsuccessful, the initial value /// is returned if assignable to the target type. /// - public static object ConvertOrCast(object initialValue, CultureInfo culture, Type targetType) + public static object? ConvertOrCast(object? initialValue, CultureInfo culture, Type targetType) { if (targetType == typeof(object)) { @@ -579,27 +599,27 @@ public static object ConvertOrCast(object initialValue, CultureInfo culture, Typ return null; } - if (TryConvert(initialValue, culture, targetType, out object convertedValue)) + if (TryConvert(initialValue, culture, targetType, out object? convertedValue)) { return convertedValue; } - return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue), targetType); + return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue)!, targetType); } #endregion - private static object EnsureTypeAssignable(object value, Type initialType, Type targetType) + private static object? EnsureTypeAssignable(object? value, Type initialType, Type targetType) { - Type valueType = value?.GetType(); - if (value != null) { + Type valueType = value.GetType(); + if (targetType.IsAssignableFrom(valueType)) { return value; } - Func castConverter = CastConverters.Get(new StructMultiKey(valueType, targetType)); + Func? castConverter = CastConverters.Get(new StructMultiKey(valueType, targetType)); if (castConverter != null) { return castConverter(value); @@ -616,7 +636,7 @@ private static object EnsureTypeAssignable(object value, Type initialType, Type throw new ArgumentException("Could not cast or convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialType?.ToString() ?? "{null}", targetType)); } - public static bool VersionTryParse(string input, out Version result) + public static bool VersionTryParse(string input, [NotNullWhen(true)]out Version? result) { #if HAVE_VERSION_TRY_PARSE return Version.TryParse(input, out result); diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs index 34e65a343..af000ea90 100644 --- a/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs @@ -179,9 +179,9 @@ private static long ToUniversalTicks(DateTime dateTime, TimeSpan offset) internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, TimeSpan offset) { - long universialTicks = ToUniversalTicks(dateTime, offset); + long universalTicks = ToUniversalTicks(dateTime, offset); - return UniversialTicksToJavaScriptTicks(universialTicks); + return UniversalTicksToJavaScriptTicks(universalTicks); } internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime) @@ -193,12 +193,12 @@ internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, bool co { long ticks = (convertToUtc) ? ToUniversalTicks(dateTime) : dateTime.Ticks; - return UniversialTicksToJavaScriptTicks(ticks); + return UniversalTicksToJavaScriptTicks(ticks); } - private static long UniversialTicksToJavaScriptTicks(long universialTicks) + private static long UniversalTicksToJavaScriptTicks(long universalTicks) { - long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks) / 10000; + long javaScriptTicks = (universalTicks - InitialJavaScriptDateTicks) / 10000; return javaScriptTicks; } @@ -341,7 +341,7 @@ private static DateTime CreateDateTime(DateTimeParser dateTimeParser) return d; } - internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt) + internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling dateTimeZoneHandling, string? dateFormatString, CultureInfo culture, out DateTime dt) { if (s.Length > 0) { @@ -364,7 +364,7 @@ internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling da } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeExact(s.ToString(), dateTimeZoneHandling, dateFormatString, culture, out dt)) { @@ -377,7 +377,7 @@ internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling da return false; } - internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt) + internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZoneHandling, string? dateFormatString, CultureInfo culture, out DateTime dt) { if (s.Length > 0) { @@ -400,7 +400,7 @@ internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZon } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeExact(s, dateTimeZoneHandling, dateFormatString, culture, out dt)) { @@ -414,7 +414,7 @@ internal static bool TryParseDateTime(string s, DateTimeZoneHandling dateTimeZon } #if HAVE_DATE_TIME_OFFSET - internal static bool TryParseDateTimeOffset(StringReference s, string dateFormatString, CultureInfo culture, out DateTimeOffset dt) + internal static bool TryParseDateTimeOffset(StringReference s, string? dateFormatString, CultureInfo culture, out DateTimeOffset dt) { if (s.Length > 0) { @@ -437,7 +437,7 @@ internal static bool TryParseDateTimeOffset(StringReference s, string dateFormat } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeOffsetExact(s.ToString(), dateFormatString, culture, out dt)) { @@ -450,7 +450,7 @@ internal static bool TryParseDateTimeOffset(StringReference s, string dateFormat return false; } - internal static bool TryParseDateTimeOffset(string s, string dateFormatString, CultureInfo culture, out DateTimeOffset dt) + internal static bool TryParseDateTimeOffset(string s, string? dateFormatString, CultureInfo culture, out DateTimeOffset dt) { if (s.Length > 0) { @@ -475,7 +475,7 @@ internal static bool TryParseDateTimeOffset(string s, string dateFormatString, C } } - if (!string.IsNullOrEmpty(dateFormatString)) + if (!StringUtils.IsNullOrEmpty(dateFormatString)) { if (TryParseDateTimeOffsetExact(s, dateFormatString, culture, out dt)) { @@ -618,9 +618,9 @@ private static bool TryReadOffset(StringReference offsetText, int startIndex, ou #endregion #region Write - internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string formatString, CultureInfo culture) + internal static void WriteDateTimeString(TextWriter writer, DateTime value, DateFormatHandling format, string? formatString, CultureInfo culture) { - if (string.IsNullOrEmpty(formatString)) + if (StringUtils.IsNullOrEmpty(formatString)) { char[] chars = new char[64]; int pos = WriteDateTimeString(chars, 0, value, null, value.Kind, format); @@ -751,9 +751,9 @@ internal static int WriteDateTimeOffset(char[] chars, int start, TimeSpan offset } #if HAVE_DATE_TIME_OFFSET - internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string formatString, CultureInfo culture) + internal static void WriteDateTimeOffsetString(TextWriter writer, DateTimeOffset value, DateFormatHandling format, string? formatString, CultureInfo culture) { - if (string.IsNullOrEmpty(formatString)) + if (StringUtils.IsNullOrEmpty(formatString)) { char[] chars = new char[64]; int pos = WriteDateTimeString(chars, 0, (format == DateFormatHandling.IsoDateFormat) ? value.DateTime : value.UtcDateTime, value.Offset, DateTimeKind.Local, format); @@ -822,4 +822,4 @@ private static void GetDateValues(DateTime td, out int year, out int month, out day = n - days[m - 1] + 1; } } -} \ No newline at end of file +} diff --git a/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs b/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs index 78cea5e2a..cf769393c 100644 --- a/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs +++ b/Src/Newtonsoft.Json/Utilities/DictionaryWrapper.cs @@ -27,11 +27,13 @@ using System.Collections.Generic; using System.Collections; using System.Threading; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; - #endif namespace Newtonsoft.Json.Utilities @@ -44,12 +46,12 @@ internal interface IWrappedDictionary internal class DictionaryWrapper : IDictionary, IWrappedDictionary { - private readonly IDictionary _dictionary; - private readonly IDictionary _genericDictionary; + private readonly IDictionary? _dictionary; + private readonly IDictionary? _genericDictionary; #if HAVE_READ_ONLY_COLLECTIONS - private readonly IReadOnlyDictionary _readOnlyDictionary; + private readonly IReadOnlyDictionary? _readOnlyDictionary; #endif - private object _syncRoot; + private object? _syncRoot; public DictionaryWrapper(IDictionary dictionary) { @@ -74,11 +76,20 @@ public DictionaryWrapper(IReadOnlyDictionary dictionary) } #endif + internal IDictionary GenericDictionary + { + get + { + MiscellaneousUtils.Assert(_genericDictionary != null); + return _genericDictionary; + } + } + public void Add(TKey key, TValue value) { if (_dictionary != null) { - _dictionary.Add(key, value); + _dictionary.Add(key!, value); } else if (_genericDictionary != null) { @@ -94,7 +105,7 @@ public bool ContainsKey(TKey key) { if (_dictionary != null) { - return _dictionary.Contains(key); + return _dictionary.Contains(key!); } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -104,7 +115,7 @@ public bool ContainsKey(TKey key) #endif else { - return _genericDictionary.ContainsKey(key); + return GenericDictionary.ContainsKey(key); } } @@ -124,7 +135,7 @@ public ICollection Keys #endif else { - return _genericDictionary.Keys; + return GenericDictionary.Keys; } } } @@ -133,9 +144,9 @@ public bool Remove(TKey key) { if (_dictionary != null) { - if (_dictionary.Contains(key)) + if (_dictionary.Contains(key!)) { - _dictionary.Remove(key); + _dictionary.Remove(key!); return true; } else @@ -151,22 +162,26 @@ public bool Remove(TKey key) #endif else { - return _genericDictionary.Remove(key); + return GenericDictionary.Remove(key); } } - public bool TryGetValue(TKey key, out TValue value) +#pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). + public bool TryGetValue(TKey key, out TValue? value) +#pragma warning restore CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). { if (_dictionary != null) { - if (!_dictionary.Contains(key)) + if (!_dictionary.Contains(key!)) { +#pragma warning disable CS8653 // A default expression introduces a null value for a type parameter. value = default; +#pragma warning restore CS8653 // A default expression introduces a null value for a type parameter. return false; } else { - value = (TValue)_dictionary[key]; + value = (TValue)_dictionary[key!]!; return true; } } @@ -178,7 +193,7 @@ public bool TryGetValue(TKey key, out TValue value) #endif else { - return _genericDictionary.TryGetValue(key, out value); + return GenericDictionary.TryGetValue(key, out value); } } @@ -198,7 +213,7 @@ public ICollection Values #endif else { - return _genericDictionary.Values; + return GenericDictionary.Values; } } } @@ -209,7 +224,7 @@ public TValue this[TKey key] { if (_dictionary != null) { - return (TValue)_dictionary[key]; + return (TValue)_dictionary[key!]!; } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -219,14 +234,14 @@ public TValue this[TKey key] #endif else { - return _genericDictionary[key]; + return GenericDictionary[key]; } } set { if (_dictionary != null) { - _dictionary[key] = value; + _dictionary[key!] = value; } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -236,7 +251,7 @@ public TValue this[TKey key] #endif else { - _genericDictionary[key] = value; + GenericDictionary[key] = value; } } } @@ -273,7 +288,7 @@ public void Clear() #endif else { - _genericDictionary.Clear(); + GenericDictionary.Clear(); } } @@ -291,7 +306,7 @@ public bool Contains(KeyValuePair item) #endif else { - return _genericDictionary.Contains(item); + return GenericDictionary.Contains(item); } } @@ -306,7 +321,7 @@ public void CopyTo(KeyValuePair[] array, int arrayIndex) while (e.MoveNext()) { DictionaryEntry entry = e.Entry; - array[arrayIndex++] = new KeyValuePair((TKey)entry.Key, (TValue)entry.Value); + array[arrayIndex++] = new KeyValuePair((TKey)entry.Key, (TValue)entry.Value!); } } finally @@ -322,7 +337,7 @@ public void CopyTo(KeyValuePair[] array, int arrayIndex) #endif else { - _genericDictionary.CopyTo(array, arrayIndex); + GenericDictionary.CopyTo(array, arrayIndex); } } @@ -342,7 +357,7 @@ public int Count #endif else { - return _genericDictionary.Count; + return GenericDictionary.Count; } } } @@ -363,7 +378,7 @@ public bool IsReadOnly #endif else { - return _genericDictionary.IsReadOnly; + return GenericDictionary.IsReadOnly; } } } @@ -372,13 +387,13 @@ public bool Remove(KeyValuePair item) { if (_dictionary != null) { - if (_dictionary.Contains(item.Key)) + if (_dictionary.Contains(item.Key!)) { - object value = _dictionary[item.Key]; + object? value = _dictionary[item.Key!]; if (Equals(value, item.Value)) { - _dictionary.Remove(item.Key); + _dictionary.Remove(item.Key!); return true; } else @@ -399,7 +414,7 @@ public bool Remove(KeyValuePair item) #endif else { - return _genericDictionary.Remove(item); + return GenericDictionary.Remove(item); } } @@ -407,7 +422,7 @@ public IEnumerator> GetEnumerator() { if (_dictionary != null) { - return _dictionary.Cast().Select(de => new KeyValuePair((TKey)de.Key, (TValue)de.Value)).GetEnumerator(); + return _dictionary.Cast().Select(de => new KeyValuePair((TKey)de.Key, (TValue)de.Value!)).GetEnumerator(); } #if HAVE_READ_ONLY_COLLECTIONS else if (_readOnlyDictionary != null) @@ -417,7 +432,7 @@ public IEnumerator> GetEnumerator() #endif else { - return _genericDictionary.GetEnumerator(); + return GenericDictionary.GetEnumerator(); } } @@ -426,7 +441,7 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - void IDictionary.Add(object key, object value) + void IDictionary.Add(object key, object? value) { if (_dictionary != null) { @@ -440,11 +455,11 @@ void IDictionary.Add(object key, object value) #endif else { - _genericDictionary.Add((TKey)key, (TValue)value); + GenericDictionary.Add((TKey)key, (TValue)value!); } } - object IDictionary.this[object key] + object? IDictionary.this[object key] { get { @@ -460,7 +475,7 @@ object IDictionary.this[object key] #endif else { - return _genericDictionary[(TKey)key]; + return GenericDictionary[(TKey)key]; } } set @@ -477,7 +492,13 @@ object IDictionary.this[object key] #endif else { - _genericDictionary[(TKey)key] = (TValue)value; + // Consider changing this code to call GenericDictionary.Remove when value is null. + // +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + GenericDictionary[(TKey)key] = (TValue)value; +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning restore CS8601 // Possible null reference assignment. } } } @@ -496,9 +517,9 @@ public DictionaryEnumerator(IEnumerator Entry.Key; - public object Value => Entry.Value; + public object? Value => Entry.Value; - public object Current => new DictionaryEntry(_e.Current.Key, _e.Current.Value); + public object Current => new DictionaryEntry(_e.Current.Key!, _e.Current.Value); public bool MoveNext() { @@ -525,7 +546,7 @@ IDictionaryEnumerator IDictionary.GetEnumerator() #endif else { - return new DictionaryEnumerator(_genericDictionary.GetEnumerator()); + return new DictionaryEnumerator(GenericDictionary.GetEnumerator()); } } @@ -543,7 +564,7 @@ bool IDictionary.Contains(object key) #endif else { - return _dictionary.Contains(key); + return _dictionary!.Contains(key); } } @@ -563,7 +584,7 @@ bool IDictionary.IsFixedSize #endif else { - return _dictionary.IsFixedSize; + return _dictionary!.IsFixedSize; } } } @@ -584,7 +605,7 @@ ICollection IDictionary.Keys #endif else { - return _dictionary.Keys; + return _dictionary!.Keys; } } } @@ -603,7 +624,7 @@ public void Remove(object key) #endif else { - _genericDictionary.Remove((TKey)key); + GenericDictionary.Remove((TKey)key); } } @@ -623,7 +644,7 @@ ICollection IDictionary.Values #endif else { - return _dictionary.Values; + return _dictionary!.Values; } } } @@ -642,7 +663,7 @@ void ICollection.CopyTo(Array array, int index) #endif else { - _genericDictionary.CopyTo((KeyValuePair[])array, index); + GenericDictionary.CopyTo((KeyValuePair[])array, index); } } @@ -690,7 +711,7 @@ public object UnderlyingDictionary #endif else { - return _genericDictionary; + return GenericDictionary; } } } diff --git a/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs b/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs index caeb9194c..76734ca3b 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicProxy.cs @@ -36,19 +36,19 @@ public virtual IEnumerable GetDynamicMemberNames(T instance) return CollectionUtils.ArrayEmpty(); } - public virtual bool TryBinaryOperation(T instance, BinaryOperationBinder binder, object arg, out object result) + public virtual bool TryBinaryOperation(T instance, BinaryOperationBinder binder, object arg, out object? result) { result = null; return false; } - public virtual bool TryConvert(T instance, ConvertBinder binder, out object result) + public virtual bool TryConvert(T instance, ConvertBinder binder, out object? result) { result = null; return false; } - public virtual bool TryCreateInstance(T instance, CreateInstanceBinder binder, object[] args, out object result) + public virtual bool TryCreateInstance(T instance, CreateInstanceBinder binder, object[] args, out object? result) { result = null; return false; @@ -64,25 +64,25 @@ public virtual bool TryDeleteMember(T instance, DeleteMemberBinder binder) return false; } - public virtual bool TryGetIndex(T instance, GetIndexBinder binder, object[] indexes, out object result) + public virtual bool TryGetIndex(T instance, GetIndexBinder binder, object[] indexes, out object? result) { result = null; return false; } - public virtual bool TryGetMember(T instance, GetMemberBinder binder, out object result) + public virtual bool TryGetMember(T instance, GetMemberBinder binder, out object? result) { result = null; return false; } - public virtual bool TryInvoke(T instance, InvokeBinder binder, object[] args, out object result) + public virtual bool TryInvoke(T instance, InvokeBinder binder, object[] args, out object? result) { result = null; return false; } - public virtual bool TryInvokeMember(T instance, InvokeMemberBinder binder, object[] args, out object result) + public virtual bool TryInvokeMember(T instance, InvokeMemberBinder binder, object[] args, out object? result) { result = null; return false; @@ -98,7 +98,7 @@ public virtual bool TrySetMember(T instance, SetMemberBinder binder, object valu return false; } - public virtual bool TryUnaryOperation(T instance, UnaryOperationBinder binder, out object result) + public virtual bool TryUnaryOperation(T instance, UnaryOperationBinder binder, out object? result) { result = null; return false; diff --git a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs index 56b556560..a00cc2ced 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicProxyMetaObject.cs @@ -37,7 +37,7 @@ internal sealed class DynamicProxyMetaObject : DynamicMetaObject private readonly DynamicProxy _proxy; internal DynamicProxyMetaObject(Expression expression, T value, DynamicProxy proxy) - : base(expression, BindingRestrictions.Empty, value) + : base(expression, BindingRestrictions.Empty, value!) { _proxy = proxy; } @@ -109,7 +109,7 @@ public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, Dy new GetBinderAdapter(binder), NoArgs, fallback(null), - e => binder.FallbackInvoke(e, args, null) + e => binder.FallbackInvoke(e!, args, null) ), null ); @@ -164,7 +164,7 @@ public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, Dyna : base.BindDeleteIndex(binder, indexes); } - private delegate DynamicMetaObject Fallback(DynamicMetaObject errorSuggestion); + private delegate DynamicMetaObject Fallback(DynamicMetaObject? errorSuggestion); private static Expression[] NoArgs => CollectionUtils.ArrayEmpty(); @@ -197,7 +197,7 @@ private static ConstantExpression Constant(DynamicMetaObjectBinder binder) Type t = binder.GetType(); while (!t.IsVisible()) { - t = t.BaseType(); + t = t.BaseType()!; } return Expression.Constant(binder, t); } @@ -206,7 +206,7 @@ private static ConstantExpression Constant(DynamicMetaObjectBinder binder) /// Helper method for generating a MetaObject which calls a /// specific method on Dynamic that returns a result /// - private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, Fallback fallback, Fallback fallbackInvoke = null) + private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, Fallback fallback, Fallback? fallbackInvoke = null) { // // First, call fallback to do default binding @@ -217,7 +217,7 @@ private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObj return BuildCallMethodWithResult(methodName, binder, args, fallbackResult, fallbackInvoke); } - private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, DynamicMetaObject fallbackResult, Fallback fallbackInvoke) + private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, IEnumerable args, DynamicMetaObject fallbackResult, Fallback? fallbackInvoke) { // // Build a new expression like: @@ -256,7 +256,7 @@ private DynamicMetaObject BuildCallMethodWithResult(string methodName, DynamicMe Expression.Condition( Expression.Call( Expression.Constant(_proxy), - typeof(DynamicProxy).GetMethod(methodName), + typeof(DynamicProxy).GetMethod(methodName)!, callArgs ), resultMetaObject.Expression, @@ -304,7 +304,7 @@ private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObj Expression.Condition( Expression.Call( Expression.Constant(_proxy), - typeof(DynamicProxy).GetMethod(methodName), + typeof(DynamicProxy).GetMethod(methodName)!, callArgs ), result, @@ -342,7 +342,7 @@ private DynamicMetaObject CallMethodNoResult(string methodName, DynamicMetaObjec Expression.Condition( Expression.Call( Expression.Constant(_proxy), - typeof(DynamicProxy).GetMethod(methodName), + typeof(DynamicProxy).GetMethod(methodName)!, callArgs ), Expression.Empty(), @@ -366,7 +366,7 @@ private BindingRestrictions GetRestrictions() public override IEnumerable GetDynamicMemberNames() { - return _proxy.GetDynamicMemberNames((T)Value); + return _proxy.GetDynamicMemberNames((T)Value!); } // It is okay to throw NotSupported from this binder. This object @@ -380,7 +380,7 @@ internal GetBinderAdapter(InvokeMemberBinder binder) : { } - public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) + public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject? errorSuggestion) { throw new NotSupportedException(); } diff --git a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs index 10b3e10b6..10b4acb3b 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs @@ -40,7 +40,7 @@ internal class DynamicReflectionDelegateFactory : ReflectionDelegateFactory { internal static DynamicReflectionDelegateFactory Instance { get; } = new DynamicReflectionDelegateFactory(); - private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner) + private static DynamicMethod CreateDynamicMethod(string name, Type? returnType, Type[] parameterTypes, Type owner) { DynamicMethod dynamicMethod = !owner.IsInterface() ? new DynamicMethod(name, returnType, parameterTypes, owner, true) @@ -51,7 +51,7 @@ private static DynamicMethod CreateDynamicMethod(string name, Type returnType, T public override ObjectConstructor CreateParameterizedConstructor(MethodBase method) { - DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object[]) }, method.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString()!, typeof(object), new[] { typeof(object[]) }, method.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateMethodCallIL(method, generator, 0); @@ -59,14 +59,14 @@ public override ObjectConstructor CreateParameterizedConstructor(MethodB return (ObjectConstructor)dynamicMethod.CreateDelegate(typeof(ObjectConstructor)); } - public override MethodCall CreateMethodCall(MethodBase method) + public override MethodCall CreateMethodCall(MethodBase method) { - DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString()!, typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateMethodCallIL(method, generator, 1); - return (MethodCall)dynamicMethod.CreateDelegate(typeof(MethodCall)); + return (MethodCall)dynamicMethod.CreateDelegate(typeof(MethodCall)); } private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator, int argsIndex) @@ -80,19 +80,22 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator generator.Emit(OpCodes.Ldlen); generator.Emit(OpCodes.Ldc_I4, args.Length); generator.Emit(OpCodes.Beq, argsOk); - generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(ReflectionUtils.EmptyTypes)); + generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(ReflectionUtils.EmptyTypes)!); generator.Emit(OpCodes.Throw); generator.MarkLabel(argsOk); if (!method.IsConstructor && !method.IsStatic) { - generator.PushInstance(method.DeclaringType); + generator.PushInstance(method.DeclaringType!); } LocalBuilder localConvertible = generator.DeclareLocal(typeof(IConvertible)); LocalBuilder localObject = generator.DeclareLocal(typeof(object)); + OpCode variableAddressOpCode = args.Length < 256 ? OpCodes.Ldloca_S : OpCodes.Ldloca; + OpCode variableLoadOpCode = args.Length < 256 ? OpCodes.Ldloc_S : OpCodes.Ldloc; + for (int i = 0; i < args.Length; i++) { ParameterInfo parameter = args[i]; @@ -100,7 +103,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator if (parameterType.IsByRef) { - parameterType = parameterType.GetElementType(); + parameterType = parameterType.GetElementType()!; LocalBuilder localVariable = generator.DeclareLocal(parameterType); @@ -118,7 +121,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator generator.Emit(OpCodes.Brtrue_S, skipSettingDefault); // parameter has no value, initialize to default - generator.Emit(OpCodes.Ldloca_S, localVariable); + generator.Emit(variableAddressOpCode, localVariable); generator.Emit(OpCodes.Initobj, parameterType); generator.Emit(OpCodes.Br_S, finishedProcessingParameter); @@ -138,7 +141,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator } } - generator.Emit(OpCodes.Ldloca_S, localVariable); + generator.Emit(variableAddressOpCode, localVariable); } else if (parameterType.IsValueType()) { @@ -156,9 +159,9 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator // parameter has no value, initialize to default LocalBuilder localVariable = generator.DeclareLocal(parameterType); - generator.Emit(OpCodes.Ldloca_S, localVariable); + generator.Emit(variableAddressOpCode, localVariable); generator.Emit(OpCodes.Initobj, parameterType); - generator.Emit(OpCodes.Ldloc_S, localVariable); + generator.Emit(variableLoadOpCode, localVariable); generator.Emit(OpCodes.Br_S, finishedProcessingParameter); // argument has value, try to convert it to parameter type @@ -167,7 +170,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator if (parameterType.IsPrimitive()) { // for primitive types we need to handle type widening (e.g. short -> int) - MethodInfo toParameterTypeMethod = typeof(IConvertible) + MethodInfo? toParameterTypeMethod = typeof(IConvertible) .GetMethod("To" + parameterType.Name, new[] { typeof(IFormatProvider) }); if (toParameterTypeMethod != null) @@ -224,7 +227,7 @@ private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator } Type returnType = method.IsConstructor - ? method.DeclaringType + ? method.DeclaringType! : ((MethodInfo)method).ReturnType; if (returnType != typeof(void)) @@ -265,7 +268,7 @@ private void GenerateCreateDefaultConstructorIL(Type type, ILGenerator generator } else { - ConstructorInfo constructorInfo = + ConstructorInfo? constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, ReflectionUtils.EmptyTypes, null); if (constructorInfo == null) @@ -279,19 +282,19 @@ private void GenerateCreateDefaultConstructorIL(Type type, ILGenerator generator generator.Return(); } - public override Func CreateGet(PropertyInfo propertyInfo) + public override Func CreateGet(PropertyInfo propertyInfo) { - DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(object), new[] { typeof(T) }, propertyInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(object), new[] { typeof(T) }, propertyInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateGetPropertyIL(propertyInfo, generator); - return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator) { - MethodInfo getMethod = propertyInfo.GetGetMethod(true); + MethodInfo? getMethod = propertyInfo.GetGetMethod(true); if (getMethod == null) { throw new ArgumentException("Property '{0}' does not have a getter.".FormatWith(CultureInfo.InvariantCulture, propertyInfo.Name)); @@ -299,7 +302,7 @@ private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator if (!getMethod.IsStatic) { - generator.PushInstance(propertyInfo.DeclaringType); + generator.PushInstance(propertyInfo.DeclaringType!); } generator.CallMethod(getMethod); @@ -307,28 +310,28 @@ private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator.Return(); } - public override Func CreateGet(FieldInfo fieldInfo) + public override Func CreateGet(FieldInfo fieldInfo) { if (fieldInfo.IsLiteral) { - object constantValue = fieldInfo.GetValue(null); - Func getter = o => constantValue; + object constantValue = fieldInfo.GetValue(null)!; + Func getter = o => constantValue; return getter; } - DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateGetFieldIL(fieldInfo, generator); - return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private void GenerateCreateGetFieldIL(FieldInfo fieldInfo, ILGenerator generator) { if (!fieldInfo.IsStatic) { - generator.PushInstance(fieldInfo.DeclaringType); + generator.PushInstance(fieldInfo.DeclaringType!); generator.Emit(OpCodes.Ldfld, fieldInfo); } else @@ -340,21 +343,21 @@ private void GenerateCreateGetFieldIL(FieldInfo fieldInfo, ILGenerator generator generator.Return(); } - public override Action CreateSet(FieldInfo fieldInfo) + public override Action CreateSet(FieldInfo fieldInfo) { - DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(T), typeof(object) }, fieldInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(T), typeof(object) }, fieldInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateSetFieldIL(fieldInfo, generator); - return (Action)dynamicMethod.CreateDelegate(typeof(Action)); + return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } internal static void GenerateCreateSetFieldIL(FieldInfo fieldInfo, ILGenerator generator) { if (!fieldInfo.IsStatic) { - generator.PushInstance(fieldInfo.DeclaringType); + generator.PushInstance(fieldInfo.DeclaringType!); } generator.Emit(OpCodes.Ldarg_1); @@ -372,22 +375,22 @@ internal static void GenerateCreateSetFieldIL(FieldInfo fieldInfo, ILGenerator g generator.Return(); } - public override Action CreateSet(PropertyInfo propertyInfo) + public override Action CreateSet(PropertyInfo propertyInfo) { - DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(T), typeof(object) }, propertyInfo.DeclaringType); + DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(T), typeof(object) }, propertyInfo.DeclaringType!); ILGenerator generator = dynamicMethod.GetILGenerator(); GenerateCreateSetPropertyIL(propertyInfo, generator); - return (Action)dynamicMethod.CreateDelegate(typeof(Action)); + return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } internal static void GenerateCreateSetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator) { - MethodInfo setMethod = propertyInfo.GetSetMethod(true); + MethodInfo setMethod = propertyInfo.GetSetMethod(true)!; if (!setMethod.IsStatic) { - generator.PushInstance(propertyInfo.DeclaringType); + generator.PushInstance(propertyInfo.DeclaringType!); } generator.Emit(OpCodes.Ldarg_1); diff --git a/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs b/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs index 5822ba082..51aa74133 100644 --- a/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/DynamicUtils.cs @@ -38,6 +38,7 @@ using System.Text; using System.Globalization; using Newtonsoft.Json.Serialization; +using System.Diagnostics; namespace Newtonsoft.Json.Utilities { @@ -53,17 +54,17 @@ internal static class BinderWrapper private const string CSharpArgumentInfoFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, " + CSharpAssemblyName; private const string CSharpBinderFlagsTypeName = "Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, " + CSharpAssemblyName; - private static object _getCSharpArgumentInfoArray; - private static object _setCSharpArgumentInfoArray; - private static MethodCall _getMemberCall; - private static MethodCall _setMemberCall; + private static object? _getCSharpArgumentInfoArray; + private static object? _setCSharpArgumentInfoArray; + private static MethodCall? _getMemberCall; + private static MethodCall? _setMemberCall; private static bool _init; private static void Init() { if (!_init) { - Type binderType = Type.GetType(BinderTypeName, false); + Type? binderType = Type.GetType(BinderTypeName, false); if (binderType == null) { throw new InvalidOperationException("Could not resolve type '{0}'. You may need to add a reference to Microsoft.CSharp.dll to work with dynamic types.".FormatWith(CultureInfo.InvariantCulture, BinderTypeName)); @@ -81,15 +82,15 @@ private static void Init() private static object CreateSharpArgumentInfoArray(params int[] values) { - Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName); - Type csharpArgumentInfoFlags = Type.GetType(CSharpArgumentInfoFlagsTypeName); + Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true)!; + Type csharpArgumentInfoFlags = Type.GetType(CSharpArgumentInfoFlagsTypeName, true)!; Array a = Array.CreateInstance(csharpArgumentInfoType, values.Length); for (int i = 0; i < values.Length; i++) { - MethodInfo createArgumentInfoMethod = csharpArgumentInfoType.GetMethod("Create", new[] { csharpArgumentInfoFlags, typeof(string) }); - object arg = createArgumentInfoMethod.Invoke(null, new object[] { 0, null }); + MethodInfo createArgumentInfoMethod = csharpArgumentInfoType.GetMethod("Create", new[] { csharpArgumentInfoFlags, typeof(string) })!; + object arg = createArgumentInfoMethod.Invoke(null, new object?[] { 0, null })!; a.SetValue(arg, i); } @@ -98,17 +99,17 @@ private static object CreateSharpArgumentInfoArray(params int[] values) private static void CreateMemberCalls() { - Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true); - Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName, true); - Type binderType = Type.GetType(BinderTypeName, true); + Type csharpArgumentInfoType = Type.GetType(CSharpArgumentInfoTypeName, true)!; + Type csharpBinderFlagsType = Type.GetType(CSharpBinderFlagsTypeName, true)!; + Type binderType = Type.GetType(BinderTypeName, true)!; Type csharpArgumentInfoTypeEnumerableType = typeof(IEnumerable<>).MakeGenericType(csharpArgumentInfoType); - MethodInfo getMemberMethod = binderType.GetMethod("GetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType }); - _getMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getMemberMethod); + MethodInfo getMemberMethod = binderType.GetMethod("GetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType })!; + _getMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getMemberMethod); - MethodInfo setMemberMethod = binderType.GetMethod("SetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType }); - _setMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMemberMethod); + MethodInfo setMemberMethod = binderType.GetMethod("SetMember", new[] { csharpBinderFlagsType, typeof(string), typeof(Type), csharpArgumentInfoTypeEnumerableType })!; + _setMemberCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(setMemberMethod); } #endif @@ -116,7 +117,9 @@ public static CallSiteBinder GetMember(string name, Type context) { #if !HAVE_REFLECTION_BINDER Init(); - return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray); + MiscellaneousUtils.Assert(_getMemberCall != null); + MiscellaneousUtils.Assert(_getCSharpArgumentInfoArray != null); + return (CallSiteBinder)_getMemberCall(null, 0, name, context, _getCSharpArgumentInfoArray)!; #else return Binder.GetMember( CSharpBinderFlags.None, name, context, new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)}); @@ -127,7 +130,9 @@ public static CallSiteBinder SetMember(string name, Type context) { #if !HAVE_REFLECTION_BINDER Init(); - return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray); + MiscellaneousUtils.Assert(_setMemberCall != null); + MiscellaneousUtils.Assert(_setCSharpArgumentInfoArray != null); + return (CallSiteBinder)_setMemberCall(null, 0, name, context, _setCSharpArgumentInfoArray)!; #else return Binder.SetMember( CSharpBinderFlags.None, name, context, new[] @@ -156,7 +161,7 @@ public NoThrowGetBinderMember(GetMemberBinder innerBinder) _innerBinder = innerBinder; } - public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) + public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject? errorSuggestion) { DynamicMetaObject retMetaObject = _innerBinder.Bind(target, CollectionUtils.ArrayEmpty()); @@ -178,7 +183,7 @@ public NoThrowSetBinderMember(SetMemberBinder innerBinder) _innerBinder = innerBinder; } - public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion) + public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject? errorSuggestion) { DynamicMetaObject retMetaObject = _innerBinder.Bind(target, new DynamicMetaObject[] { value }); diff --git a/Src/Newtonsoft.Json/Utilities/EnumUtils.cs b/Src/Newtonsoft.Json/Utilities/EnumUtils.cs index 729670be7..a1b3bae9b 100644 --- a/Src/Newtonsoft.Json/Utilities/EnumUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/EnumUtils.cs @@ -36,6 +36,8 @@ using System.Reflection; using System.Text; using Newtonsoft.Json.Serialization; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace Newtonsoft.Json.Utilities { @@ -44,27 +46,30 @@ internal static class EnumUtils private const char EnumSeparatorChar = ','; private const string EnumSeparatorString = ", "; - private static readonly ThreadSafeStore, EnumInfo> ValuesAndNamesPerEnum = new ThreadSafeStore, EnumInfo>(InitializeValuesAndNames); + private static readonly ThreadSafeStore, EnumInfo> ValuesAndNamesPerEnum = new ThreadSafeStore, EnumInfo>(InitializeValuesAndNames); - private static EnumInfo InitializeValuesAndNames(StructMultiKey key) + private static EnumInfo InitializeValuesAndNames(StructMultiKey key) { Type enumType = key.Value1; string[] names = Enum.GetNames(enumType); string[] resolvedNames = new string[names.Length]; ulong[] values = new ulong[names.Length]; + bool hasSpecifiedName; for (int i = 0; i < names.Length; i++) { string name = names[i]; - FieldInfo f = enumType.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); - values[i] = ToUInt64(f.GetValue(null)); + FieldInfo f = enumType.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!; + values[i] = ToUInt64(f.GetValue(null)!); string resolvedName; #if HAVE_DATA_CONTRACTS - resolvedName = f.GetCustomAttributes(typeof(EnumMemberAttribute), true) + string? specifiedName = f.GetCustomAttributes(typeof(EnumMemberAttribute), true) .Cast() .Select(a => a.Value) - .SingleOrDefault() ?? f.Name; + .SingleOrDefault(); + hasSpecifiedName = specifiedName != null; + resolvedName = specifiedName ?? name; if (Array.IndexOf(resolvedNames, resolvedName, 0, i) != -1) { @@ -72,10 +77,11 @@ private static EnumInfo InitializeValuesAndNames(StructMultiKey GetFlagsValues(T value) where T : struct // Used by Newtonsoft.Json.Schema private static CamelCaseNamingStrategy _camelCaseNamingStrategy = new CamelCaseNamingStrategy(); - public static bool TryToString(Type enumType, object value, bool camelCase, out string name) + public static bool TryToString(Type enumType, object value, bool camelCase, [NotNullWhen(true)]out string? name) { return TryToString(enumType, value, camelCase ? _camelCaseNamingStrategy : null, out name); } - public static bool TryToString(Type enumType, object value, NamingStrategy namingStrategy, out string name) + public static bool TryToString(Type enumType, object value, NamingStrategy? namingStrategy, [NotNullWhen(true)]out string? name) { - EnumInfo enumInfo = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); + EnumInfo enumInfo = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); ulong v = ToUInt64(value); if (!enumInfo.IsFlags) @@ -149,7 +155,7 @@ public static bool TryToString(Type enumType, object value, NamingStrategy namin } } - private static string InternalFlagsFormat(EnumInfo entry, ulong result) + private static string? InternalFlagsFormat(EnumInfo entry, ulong result) { string[] resolvedNames = entry.ResolvedNames; ulong[] values = entry.Values; @@ -185,7 +191,7 @@ private static string InternalFlagsFormat(EnumInfo entry, ulong result) index--; } - string returnString; + string? returnString; if (result != 0) { // We were unable to represent this number as a bitwise or of valid flags @@ -213,7 +219,7 @@ private static string InternalFlagsFormat(EnumInfo entry, ulong result) public static EnumInfo GetEnumValuesAndNames(Type enumType) { - return ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, null)); + return ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, null)); } private static ulong ToUInt64(object value) @@ -249,7 +255,7 @@ private static ulong ToUInt64(object value) } } - public static object ParseEnum(Type enumType, NamingStrategy namingStrategy, string value, bool disallowNumber) + public static object ParseEnum(Type enumType, NamingStrategy? namingStrategy, string value, bool disallowNumber) { ValidationUtils.ArgumentNotNull(enumType, nameof(enumType)); ValidationUtils.ArgumentNotNull(value, nameof(value)); @@ -259,7 +265,7 @@ public static object ParseEnum(Type enumType, NamingStrategy namingStrategy, str throw new ArgumentException("Type provided must be an Enum.", nameof(enumType)); } - EnumInfo entry = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); + EnumInfo entry = ValuesAndNamesPerEnum.Get(new StructMultiKey(enumType, namingStrategy)); string[] enumNames = entry.Names; string[] resolvedNames = entry.ResolvedNames; ulong[] enumValues = entry.Values; @@ -292,7 +298,7 @@ public static object ParseEnum(Type enumType, NamingStrategy namingStrategy, str Type underlyingType = Enum.GetUnderlyingType(enumType); value = value.Trim(); - object temp = null; + object? temp = null; try { diff --git a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs index 6d6f8d7b0..36acc7c0c 100644 --- a/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs @@ -57,7 +57,7 @@ public override ObjectConstructor CreateParameterizedConstructor(MethodB return compiled; } - public override MethodCall CreateMethodCall(MethodBase method) + public override MethodCall CreateMethodCall(MethodBase method) { ValidationUtils.ArgumentNotNull(method, nameof(method)); @@ -70,7 +70,7 @@ public override MethodCall CreateMethodCall(MethodBase method) LambdaExpression lambdaExpression = Expression.Lambda(typeof(MethodCall), callExpression, targetParameterExpression, argsParameterExpression); - MethodCall compiled = (MethodCall)lambdaExpression.Compile(); + MethodCall compiled = (MethodCall)lambdaExpression.Compile(); return compiled; } @@ -79,9 +79,16 @@ private class ByRefParameter public Expression Value; public ParameterExpression Variable; public bool IsOut; + + public ByRefParameter(Expression value, ParameterExpression variable, bool isOut) + { + Value = value; + Variable = variable; + IsOut = isOut; + } } - private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression targetParameterExpression, ParameterExpression argsParameterExpression) + private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpression? targetParameterExpression, ParameterExpression argsParameterExpression) { ParameterInfo[] parametersInfo = method.GetParameters(); @@ -104,7 +111,7 @@ private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpres bool isByRef = false; if (parameterType.IsByRef) { - parameterType = parameterType.GetElementType(); + parameterType = parameterType.GetElementType()!; isByRef = true; } @@ -117,7 +124,7 @@ private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpres if (isByRef) { ParameterExpression variable = Expression.Variable(parameterType); - refParameterMap.Add(new ByRefParameter {Value = argExpression, Variable = variable, IsOut = parameter.IsOut}); + refParameterMap.Add(new ByRefParameter(argExpression, variable, parameter.IsOut)); argExpression = variable; } @@ -137,7 +144,7 @@ private Expression BuildMethodCall(MethodBase method, Type type, ParameterExpres } else { - Expression readParameter = EnsureCastExpression(targetParameterExpression, method.DeclaringType); + Expression readParameter = EnsureCastExpression(targetParameterExpression!, method.DeclaringType!); callExpression = Expression.Call(readParameter, (MethodInfo)method, argsExpression); } @@ -187,7 +194,7 @@ public override Func CreateDefaultConstructor(Type type) // avoid error from expressions compiler because of abstract class if (type.IsAbstract()) { - return () => (T)Activator.CreateInstance(type); + return () => (T)Activator.CreateInstance(type)!; } try @@ -207,11 +214,11 @@ public override Func CreateDefaultConstructor(Type type) { // an error can be thrown if constructor is not valid on Win8 // will have INVOCATION_FLAGS_NON_W8P_FX_API invocation flag - return () => (T)Activator.CreateInstance(type); + return () => (T)Activator.CreateInstance(type)!; } } - public override Func CreateGet(PropertyInfo propertyInfo) + public override Func CreateGet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); @@ -221,7 +228,11 @@ public override Func CreateGet(PropertyInfo propertyInfo) ParameterExpression parameterExpression = Expression.Parameter(instanceType, "instance"); Expression resultExpression; - MethodInfo getMethod = propertyInfo.GetGetMethod(true); + MethodInfo? getMethod = propertyInfo.GetGetMethod(true); + if (getMethod == null) + { + throw new ArgumentException("Property does not have a getter."); + } if (getMethod.IsStatic) { @@ -229,7 +240,7 @@ public override Func CreateGet(PropertyInfo propertyInfo) } else { - Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType); + Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType!); resultExpression = Expression.MakeMemberAccess(readParameter, propertyInfo); } @@ -238,11 +249,11 @@ public override Func CreateGet(PropertyInfo propertyInfo) LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func), resultExpression, parameterExpression); - Func compiled = (Func)lambdaExpression.Compile(); + Func compiled = (Func)lambdaExpression.Compile(); return compiled; } - public override Func CreateGet(FieldInfo fieldInfo) + public override Func CreateGet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); @@ -255,24 +266,24 @@ public override Func CreateGet(FieldInfo fieldInfo) } else { - Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType); + Expression sourceExpression = EnsureCastExpression(sourceParameter, fieldInfo.DeclaringType!); fieldExpression = Expression.Field(sourceExpression, fieldInfo); } fieldExpression = EnsureCastExpression(fieldExpression, typeof(object)); - Func compiled = Expression.Lambda>(fieldExpression, sourceParameter).Compile(); + Func compiled = Expression.Lambda>(fieldExpression, sourceParameter).Compile(); return compiled; } - public override Action CreateSet(FieldInfo fieldInfo) + public override Action CreateSet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); // use reflection for structs // expression doesn't correctly set value - if (fieldInfo.DeclaringType.IsValueType() || fieldInfo.IsInitOnly) + if (fieldInfo.DeclaringType!.IsValueType() || fieldInfo.IsInitOnly) { return LateBoundReflectionDelegateFactory.Instance.CreateSet(fieldInfo); } @@ -287,7 +298,7 @@ public override Action CreateSet(FieldInfo fieldInfo) } else { - Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType); + Expression sourceExpression = EnsureCastExpression(sourceParameterExpression, fieldInfo.DeclaringType!); fieldExpression = Expression.Field(sourceExpression, fieldInfo); } @@ -298,17 +309,17 @@ public override Action CreateSet(FieldInfo fieldInfo) LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), assignExpression, sourceParameterExpression, valueParameterExpression); - Action compiled = (Action)lambdaExpression.Compile(); + Action compiled = (Action)lambdaExpression.Compile(); return compiled; } - public override Action CreateSet(PropertyInfo propertyInfo) + public override Action CreateSet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); // use reflection for structs // expression doesn't correctly set value - if (propertyInfo.DeclaringType.IsValueType()) + if (propertyInfo.DeclaringType!.IsValueType()) { return LateBoundReflectionDelegateFactory.Instance.CreateSet(propertyInfo); } @@ -321,7 +332,11 @@ public override Action CreateSet(PropertyInfo propertyInfo) ParameterExpression valueParameter = Expression.Parameter(valueType, "value"); Expression readValueParameter = EnsureCastExpression(valueParameter, propertyInfo.PropertyType); - MethodInfo setMethod = propertyInfo.GetSetMethod(true); + MethodInfo? setMethod = propertyInfo.GetSetMethod(true); + if (setMethod == null) + { + throw new ArgumentException("Property does not have a setter."); + } Expression setExpression; if (setMethod.IsStatic) @@ -330,14 +345,14 @@ public override Action CreateSet(PropertyInfo propertyInfo) } else { - Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType); + Expression readInstanceParameter = EnsureCastExpression(instanceParameter, propertyInfo.DeclaringType!); setExpression = Expression.Call(readInstanceParameter, setMethod, readValueParameter); } - LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), setExpression, instanceParameter, valueParameter); + LambdaExpression lambdaExpression = Expression.Lambda(typeof(Action), setExpression, instanceParameter, valueParameter); - Action compiled = (Action)lambdaExpression.Compile(); + Action compiled = (Action)lambdaExpression.Compile(); return compiled; } @@ -357,7 +372,7 @@ private Expression EnsureCastExpression(Expression expression, Type targetType, if (allowWidening && targetType.IsPrimitive()) { - MethodInfo toTargetTypeMethod = typeof(Convert) + MethodInfo? toTargetTypeMethod = typeof(Convert) .GetMethod("To" + targetType.Name, new[] { typeof(object) }); if (toTargetTypeMethod != null) diff --git a/Src/Newtonsoft.Json/Utilities/FSharpUtils.cs b/Src/Newtonsoft.Json/Utilities/FSharpUtils.cs index 55e15d814..925219ff0 100644 --- a/Src/Newtonsoft.Json/Utilities/FSharpUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/FSharpUtils.cs @@ -31,15 +31,16 @@ using System.Reflection; using System.Text; using Newtonsoft.Json.Serialization; +using System.Diagnostics; namespace Newtonsoft.Json.Utilities { internal class FSharpFunction { - private readonly object _instance; - private readonly MethodCall _invoker; + private readonly object? _instance; + private readonly MethodCall _invoker; - public FSharpFunction(object instance, MethodCall invoker) + public FSharpFunction(object? instance, MethodCall invoker) { _instance = instance; _invoker = invoker; @@ -53,69 +54,78 @@ public object Invoke(params object[] args) } } - internal static class FSharpUtils + internal class FSharpUtils { - private static readonly object Lock = new object(); + private FSharpUtils(Assembly fsharpCoreAssembly) + { + FSharpCoreAssembly = fsharpCoreAssembly; - private static bool _initialized; - private static MethodInfo _ofSeq; - private static Type _mapType; - - public static Assembly FSharpCoreAssembly { get; private set; } - public static MethodCall IsUnion { get; private set; } - public static MethodCall GetUnionCases { get; private set; } - public static MethodCall PreComputeUnionTagReader { get; private set; } - public static MethodCall PreComputeUnionReader { get; private set; } - public static MethodCall PreComputeUnionConstructor { get; private set; } - public static Func GetUnionCaseInfoDeclaringType { get; private set; } - public static Func GetUnionCaseInfoName { get; private set; } - public static Func GetUnionCaseInfoTag { get; private set; } - public static MethodCall GetUnionCaseInfoFields { get; private set; } + Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType")!; - public const string FSharpSetTypeName = "FSharpSet`1"; - public const string FSharpListTypeName = "FSharpList`1"; - public const string FSharpMapTypeName = "FSharpMap`2"; + MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static); + IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(isUnionMethodInfo)!; - public static void EnsureInitialized(Assembly fsharpCoreAssembly) - { - if (!_initialized) - { - lock (Lock) - { - if (!_initialized) - { - FSharpCoreAssembly = fsharpCoreAssembly; + MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static); + GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getUnionCasesMethodInfo)!; - Type fsharpType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpType"); + Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue")!; - MethodInfo isUnionMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "IsUnion", BindingFlags.Public | BindingFlags.Static); - IsUnion = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(isUnionMethodInfo); + PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader"); + PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader"); + PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor"); - MethodInfo getUnionCasesMethodInfo = GetMethodWithNonPublicFallback(fsharpType, "GetUnionCases", BindingFlags.Public | BindingFlags.Static); - GetUnionCases = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(getUnionCasesMethodInfo); + Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo")!; - Type fsharpValue = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.FSharpValue"); + GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Name")!)!; + GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Tag")!)!; + GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("DeclaringType")!)!; + GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(unionCaseInfo.GetMethod("GetFields")!); + + Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule")!; + _ofSeq = listModule.GetMethod("OfSeq")!; + + _mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2")!; + } - PreComputeUnionTagReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionTagReader"); - PreComputeUnionReader = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionReader"); - PreComputeUnionConstructor = CreateFSharpFuncCall(fsharpValue, "PreComputeUnionConstructor"); + private static readonly object Lock = new object(); + private static FSharpUtils? _instance; - Type unionCaseInfo = fsharpCoreAssembly.GetType("Microsoft.FSharp.Reflection.UnionCaseInfo"); + public static FSharpUtils Instance + { + get + { + MiscellaneousUtils.Assert(_instance != null); + return _instance; + } + } - GetUnionCaseInfoName = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Name")); - GetUnionCaseInfoTag = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("Tag")); - GetUnionCaseInfoDeclaringType = JsonTypeReflector.ReflectionDelegateFactory.CreateGet(unionCaseInfo.GetProperty("DeclaringType")); - GetUnionCaseInfoFields = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(unionCaseInfo.GetMethod("GetFields")); + private MethodInfo _ofSeq; + private Type _mapType; - Type listModule = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.ListModule"); - _ofSeq = listModule.GetMethod("OfSeq"); + public Assembly FSharpCoreAssembly { get; private set; } + public MethodCall IsUnion { get; private set; } + public MethodCall GetUnionCases { get; private set; } + public MethodCall PreComputeUnionTagReader { get; private set; } + public MethodCall PreComputeUnionReader { get; private set; } + public MethodCall PreComputeUnionConstructor { get; private set; } + public Func GetUnionCaseInfoDeclaringType { get; private set; } + public Func GetUnionCaseInfoName { get; private set; } + public Func GetUnionCaseInfoTag { get; private set; } + public MethodCall GetUnionCaseInfoFields { get; private set; } - _mapType = fsharpCoreAssembly.GetType("Microsoft.FSharp.Collections.FSharpMap`2"); + public const string FSharpSetTypeName = "FSharpSet`1"; + public const string FSharpListTypeName = "FSharpList`1"; + public const string FSharpMapTypeName = "FSharpMap`2"; -#if HAVE_MEMORY_BARRIER - Thread.MemoryBarrier(); -#endif - _initialized = true; + public static void EnsureInitialized(Assembly fsharpCoreAssembly) + { + if (_instance == null) + { + lock (Lock) + { + if (_instance == null) + { + _instance = new FSharpUtils(fsharpCoreAssembly); } } } @@ -123,7 +133,7 @@ public static void EnsureInitialized(Assembly fsharpCoreAssembly) private static MethodInfo GetMethodWithNonPublicFallback(Type type, string methodName, BindingFlags bindingFlags) { - MethodInfo methodInfo = type.GetMethod(methodName, bindingFlags); + MethodInfo methodInfo = type.GetMethod(methodName, bindingFlags)!; // if no matching method then attempt to find with nonpublic flag // this is required because in WinApps some methods are private but always using NonPublic breaks medium trust @@ -131,23 +141,23 @@ private static MethodInfo GetMethodWithNonPublicFallback(Type type, string metho // https://github.com/JamesNK/Newtonsoft.Json/issues/821 if (methodInfo == null && (bindingFlags & BindingFlags.NonPublic) != BindingFlags.NonPublic) { - methodInfo = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic); + methodInfo = type.GetMethod(methodName, bindingFlags | BindingFlags.NonPublic)!; } - return methodInfo; + return methodInfo!; } - private static MethodCall CreateFSharpFuncCall(Type type, string methodName) + private static MethodCall CreateFSharpFuncCall(Type type, string methodName) { MethodInfo innerMethodInfo = GetMethodWithNonPublicFallback(type, methodName, BindingFlags.Public | BindingFlags.Static); - MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance); + MethodInfo invokeFunc = innerMethodInfo.ReturnType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance)!; - MethodCall call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(innerMethodInfo); - MethodCall invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(invokeFunc); + MethodCall call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(innerMethodInfo); + MethodCall invoke = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall(invokeFunc)!; - MethodCall createFunction = (target, args) => + MethodCall createFunction = (target, args) => { - object result = call(target, args); + object? result = call(target, args); FSharpFunction f = new FSharpFunction(result, invoke); return f; @@ -156,32 +166,32 @@ private static MethodCall CreateFSharpFuncCall(Type type, string return createFunction; } - public static ObjectConstructor CreateSeq(Type t) + public ObjectConstructor CreateSeq(Type t) { MethodInfo seqType = _ofSeq.MakeGenericMethod(t); return JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(seqType); } - public static ObjectConstructor CreateMap(Type keyType, Type valueType) + public ObjectConstructor CreateMap(Type keyType, Type valueType) { - MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator"); + MethodInfo creatorDefinition = typeof(FSharpUtils).GetMethod("BuildMapCreator")!; MethodInfo creatorGeneric = creatorDefinition.MakeGenericMethod(keyType, valueType); - return (ObjectConstructor)creatorGeneric.Invoke(null, null); + return (ObjectConstructor)creatorGeneric.Invoke(this, null)!; } - public static ObjectConstructor BuildMapCreator() + public ObjectConstructor BuildMapCreator() { Type genericMapType = _mapType.MakeGenericType(typeof(TKey), typeof(TValue)); - ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable>) }); + ConstructorInfo ctor = genericMapType.GetConstructor(new[] { typeof(IEnumerable>) })!; ObjectConstructor ctorDelegate = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(ctor); ObjectConstructor creator = args => { // convert dictionary KeyValuePairs to Tuples - IEnumerable> values = (IEnumerable>)args[0]; + IEnumerable> values = (IEnumerable>)args[0]!; IEnumerable> tupleValues = values.Select(kv => new Tuple(kv.Key, kv.Value)); return ctorDelegate(tupleValues); diff --git a/Src/Newtonsoft.Json/Utilities/ImmutableCollectionsUtils.cs b/Src/Newtonsoft.Json/Utilities/ImmutableCollectionsUtils.cs index 5d60beb90..8d7ba74d2 100644 --- a/Src/Newtonsoft.Json/Utilities/ImmutableCollectionsUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ImmutableCollectionsUtils.cs @@ -25,12 +25,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else using System.Linq; #endif using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using Newtonsoft.Json.Serialization; @@ -88,7 +90,7 @@ public ImmutableCollectionTypeInfo(string contractTypeName, string createdTypeNa new ImmutableCollectionTypeInfo(ImmutableQueueGenericTypeName, ImmutableQueueGenericTypeName, ImmutableQueueTypeName), new ImmutableCollectionTypeInfo(ImmutableStackGenericInterfaceTypeName, ImmutableStackGenericTypeName, ImmutableStackTypeName), new ImmutableCollectionTypeInfo(ImmutableStackGenericTypeName, ImmutableStackGenericTypeName, ImmutableStackTypeName), - new ImmutableCollectionTypeInfo(ImmutableSetGenericInterfaceTypeName, ImmutableSortedSetGenericTypeName, ImmutableSortedSetTypeName), + new ImmutableCollectionTypeInfo(ImmutableSetGenericInterfaceTypeName, ImmutableHashSetGenericTypeName, ImmutableHashSetTypeName), new ImmutableCollectionTypeInfo(ImmutableSortedSetGenericTypeName, ImmutableSortedSetGenericTypeName, ImmutableSortedSetTypeName), new ImmutableCollectionTypeInfo(ImmutableHashSetGenericTypeName, ImmutableHashSetGenericTypeName, ImmutableHashSetTypeName), new ImmutableCollectionTypeInfo(ImmutableArrayGenericTypeName, ImmutableArrayGenericTypeName, ImmutableArrayTypeName) @@ -104,27 +106,27 @@ public ImmutableCollectionTypeInfo(string contractTypeName, string createdTypeNa private static readonly IList DictionaryContractImmutableCollectionDefinitions = new List { - new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericInterfaceTypeName, ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryTypeName), + new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericInterfaceTypeName, ImmutableDictionaryGenericTypeName, ImmutableDictionaryTypeName), new ImmutableCollectionTypeInfo(ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryGenericTypeName, ImmutableSortedDictionaryTypeName), new ImmutableCollectionTypeInfo(ImmutableDictionaryGenericTypeName, ImmutableDictionaryGenericTypeName, ImmutableDictionaryTypeName) }; - internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, out Type createdType, out ObjectConstructor parameterizedCreator) + internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type collectionItemType, [NotNullWhen(true)]out Type? createdType, [NotNullWhen(true)]out ObjectConstructor? parameterizedCreator) { if (underlyingType.IsGenericType()) { Type underlyingTypeDefinition = underlyingType.GetGenericTypeDefinition(); - string name = underlyingTypeDefinition.FullName; + string name = underlyingTypeDefinition.FullName!; - ImmutableCollectionTypeInfo definition = ArrayContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); + ImmutableCollectionTypeInfo? definition = ArrayContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); if (definition != null) { - Type createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); - Type builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); + Type? createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); + Type? builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); if (createdTypeDefinition != null && builderTypeDefinition != null) { - MethodInfo mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => m.Name == "CreateRange" && m.GetParameters().Length == 1); + MethodInfo? mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => m.Name == "CreateRange" && m.GetParameters().Length == 1); if (mb != null) { createdType = createdTypeDefinition.MakeGenericType(collectionItemType); @@ -141,22 +143,22 @@ internal static bool TryBuildImmutableForArrayContract(Type underlyingType, Type return false; } - internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, out Type createdType, out ObjectConstructor parameterizedCreator) + internal static bool TryBuildImmutableForDictionaryContract(Type underlyingType, Type keyItemType, Type valueItemType, [NotNullWhen(true)]out Type? createdType, [NotNullWhen(true)]out ObjectConstructor? parameterizedCreator) { if (underlyingType.IsGenericType()) { Type underlyingTypeDefinition = underlyingType.GetGenericTypeDefinition(); - string name = underlyingTypeDefinition.FullName; + string name = underlyingTypeDefinition.FullName!; - ImmutableCollectionTypeInfo definition = DictionaryContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); + ImmutableCollectionTypeInfo? definition = DictionaryContractImmutableCollectionDefinitions.FirstOrDefault(d => d.ContractTypeName == name); if (definition != null) { - Type createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); - Type builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); + Type? createdTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.CreatedTypeName); + Type? builderTypeDefinition = underlyingTypeDefinition.Assembly().GetType(definition.BuilderTypeName); if (createdTypeDefinition != null && builderTypeDefinition != null) { - MethodInfo mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => + MethodInfo? mb = builderTypeDefinition.GetMethods().FirstOrDefault(m => { ParameterInfo[] parameters = m.GetParameters(); diff --git a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs index 0e6ffc28f..74695ed5f 100644 --- a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs @@ -31,6 +31,8 @@ #endif using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -41,7 +43,7 @@ namespace Newtonsoft.Json.Utilities { internal static class BufferUtils { - public static char[] RentBuffer(IArrayPool bufferPool, int minSize) + public static char[] RentBuffer(IArrayPool? bufferPool, int minSize) { if (bufferPool == null) { @@ -52,12 +54,12 @@ public static char[] RentBuffer(IArrayPool bufferPool, int minSize) return buffer; } - public static void ReturnBuffer(IArrayPool bufferPool, char[] buffer) + public static void ReturnBuffer(IArrayPool? bufferPool, char[]? buffer) { bufferPool?.Return(buffer); } - public static char[] EnsureBufferSize(IArrayPool bufferPool, int size, char[] buffer) + public static char[] EnsureBufferSize(IArrayPool? bufferPool, int size, char[]? buffer) { if (bufferPool == null) { @@ -123,15 +125,16 @@ public static bool[] GetCharEscapeFlags(StringEscapeHandling stringEscapeHandlin return SingleQuoteCharEscapeFlags; } - public static bool ShouldEscapeJavaScriptString(string s, bool[] charEscapeFlags) + public static bool ShouldEscapeJavaScriptString(string? s, bool[] charEscapeFlags) { if (s == null) { return false; } - foreach (char c in s) + for (int i = 0; i < s.Length; i++) { + char c = s[i]; if (c >= charEscapeFlags.Length || charEscapeFlags[c]) { return true; @@ -141,8 +144,8 @@ public static bool ShouldEscapeJavaScriptString(string s, bool[] charEscapeFlags return false; } - public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters, - bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool bufferPool, ref char[] writeBuffer) + public static void WriteEscapedJavaScriptString(TextWriter writer, string? s, char delimiter, bool appendDelimiters, + bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IArrayPool? bufferPool, ref char[]? writeBuffer) { // leading delimiter if (appendDelimiters) @@ -150,7 +153,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha writer.Write(delimiter); } - if (!string.IsNullOrEmpty(s)) + if (!StringUtils.IsNullOrEmpty(s)) { int lastWritePosition = FirstCharToEscape(s, charEscapeFlags, stringEscapeHandling); if (lastWritePosition == -1) @@ -181,7 +184,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha continue; } - string escapedValue; + string? escapedValue; switch (c) { @@ -230,7 +233,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha writeBuffer = BufferUtils.EnsureBufferSize(bufferPool, UnicodeTextLength, writeBuffer); } - StringUtils.ToCharAsUnicode(c, writeBuffer); + StringUtils.ToCharAsUnicode(c, writeBuffer!); // slightly hacky but it saves multiple conditions in if test escapedValue = EscapedUnicodeText; @@ -263,7 +266,7 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha // copy it over when creating new buffer if (isEscapedUnicodeText) { - Debug.Assert(writeBuffer != null, "Write buffer should never be null because it is set when the escaped unicode text is encountered."); + MiscellaneousUtils.Assert(writeBuffer != null, "Write buffer should never be null because it is set when the escaped unicode text is encountered."); Array.Copy(writeBuffer, newBuffer, UnicodeTextLength); } @@ -286,11 +289,12 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha } else { + MiscellaneousUtils.Assert(writeBuffer != null); writer.Write(writeBuffer, 0, UnicodeTextLength); } } - Debug.Assert(lastWritePosition != 0); + MiscellaneousUtils.Assert(lastWritePosition != 0); length = s.Length - lastWritePosition; if (length > 0) { @@ -314,13 +318,13 @@ public static void WriteEscapedJavaScriptString(TextWriter writer, string s, cha } } - public static string ToEscapedJavaScriptString(string value, char delimiter, bool appendDelimiters, StringEscapeHandling stringEscapeHandling) + public static string ToEscapedJavaScriptString(string? value, char delimiter, bool appendDelimiters, StringEscapeHandling stringEscapeHandling) { bool[] charEscapeFlags = GetCharEscapeFlags(stringEscapeHandling, delimiter); using (StringWriter w = StringUtils.CreateStringWriter(value?.Length ?? 16)) { - char[] buffer = null; + char[]? buffer = null; WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, charEscapeFlags, stringEscapeHandling, null, ref buffer); return w.ToString(); } @@ -371,7 +375,7 @@ public static Task WriteEscapedJavaScriptStringAsync(TextWriter writer, string s return WriteEscapedJavaScriptStringWithDelimitersAsync(writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); } - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { return cancellationToken.CancelIfRequestedAsync() ?? AsyncUtils.CompletedTask; } @@ -383,15 +387,15 @@ private static Task WriteEscapedJavaScriptStringWithDelimitersAsync(TextWriter w bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, JsonTextWriter client, char[] writeBuffer, CancellationToken cancellationToken) { Task task = writer.WriteAsync(delimiter, cancellationToken); - if (!task.IsCompletedSucessfully()) + if (!task.IsCompletedSuccessfully()) { return WriteEscapedJavaScriptStringWithDelimitersAsync(task, writer, s, delimiter, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); } - if (!string.IsNullOrEmpty(s)) + if (!StringUtils.IsNullOrEmpty(s)) { task = WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken); - if (task.IsCompletedSucessfully()) + if (task.IsCompletedSuccessfully()) { return writer.WriteAsync(delimiter, cancellationToken); } @@ -406,7 +410,7 @@ private static async Task WriteEscapedJavaScriptStringWithDelimitersAsync(Task t { await task.ConfigureAwait(false); - if (!string.IsNullOrEmpty(s)) + if (!StringUtils.IsNullOrEmpty(s)) { await WriteEscapedJavaScriptStringWithoutDelimitersAsync(writer, s, charEscapeFlags, stringEscapeHandling, client, writeBuffer, cancellationToken).ConfigureAwait(false); } @@ -450,7 +454,7 @@ private static async Task WriteDefinitelyEscapedJavaScriptStringWithoutDelimiter int length; bool isEscapedUnicodeText = false; - string escapedValue = null; + string? escapedValue = null; for (int i = lastWritePosition; i < s.Length; i++) { @@ -539,7 +543,7 @@ private static async Task WriteDefinitelyEscapedJavaScriptStringWithoutDelimiter lastWritePosition = i + 1; if (!isEscapedUnicodeText) { - await writer.WriteAsync(escapedValue, cancellationToken).ConfigureAwait(false); + await writer.WriteAsync(escapedValue!, cancellationToken).ConfigureAwait(false); } else { @@ -565,7 +569,7 @@ private static async Task WriteDefinitelyEscapedJavaScriptStringWithoutDelimiter } #endif - public static bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime dateTime, out string errorMessage) + public static bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime dateTime, [NotNullWhen(false)]out string? errorMessage) { dateTime = default; errorMessage = null; @@ -626,7 +630,7 @@ public static bool TryGetDateFromConstructorJson(JsonReader reader, out DateTime return true; } - private static bool TryGetDateConstructorValue(JsonReader reader, out long? integer, out string errorMessage) + private static bool TryGetDateConstructorValue(JsonReader reader, out long? integer, [NotNullWhen(false)] out string? errorMessage) { integer = null; errorMessage = null; @@ -646,7 +650,7 @@ private static bool TryGetDateConstructorValue(JsonReader reader, out long? inte return false; } - integer = (long)reader.Value; + integer = (long)reader.Value!; return true; } } diff --git a/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs index 2150e4a3f..67526268e 100644 --- a/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/LateBoundReflectionDelegateFactory.cs @@ -50,10 +50,10 @@ public override ObjectConstructor CreateParameterizedConstructor(MethodB return a => c.Invoke(a); } - return a => method.Invoke(null, a); + return a => method.Invoke(null, a)!; } - public override MethodCall CreateMethodCall(MethodBase method) + public override MethodCall CreateMethodCall(MethodBase method) { ValidationUtils.ArgumentNotNull(method, nameof(method)); @@ -71,36 +71,40 @@ public override Func CreateDefaultConstructor(Type type) if (type.IsValueType()) { - return () => (T)Activator.CreateInstance(type); + return () => (T)Activator.CreateInstance(type)!; } - ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true); + ConstructorInfo? constructorInfo = ReflectionUtils.GetDefaultConstructor(type, true); + if (constructorInfo == null) + { + throw new InvalidOperationException("Unable to find default constructor for " + type.FullName); + } return () => (T)constructorInfo.Invoke(null); } - public override Func CreateGet(PropertyInfo propertyInfo) + public override Func CreateGet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); return o => propertyInfo.GetValue(o, null); } - public override Func CreateGet(FieldInfo fieldInfo) + public override Func CreateGet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); return o => fieldInfo.GetValue(o); } - public override Action CreateSet(FieldInfo fieldInfo) + public override Action CreateSet(FieldInfo fieldInfo) { ValidationUtils.ArgumentNotNull(fieldInfo, nameof(fieldInfo)); return (o, v) => fieldInfo.SetValue(o, v); } - public override Action CreateSet(PropertyInfo propertyInfo) + public override Action CreateSet(PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); diff --git a/Src/Newtonsoft.Json/Utilities/LinqBridge.cs b/Src/Newtonsoft.Json/Utilities/LinqBridge.cs index dc8125838..e1dba08ae 100644 --- a/Src/Newtonsoft.Json/Utilities/LinqBridge.cs +++ b/Src/Newtonsoft.Json/Utilities/LinqBridge.cs @@ -35,6 +35,8 @@ using System.Globalization; using Newtonsoft.Json.Serialization; +#nullable disable + namespace Newtonsoft.Json.Utilities.LinqBridge { /// @@ -375,7 +377,7 @@ private static TSource FirstImpl( Func empty) { CheckNotNull(source, "source"); - Debug.Assert(empty != null); + MiscellaneousUtils.Assert(empty != null); var list = source as IList; // optimized case for lists if (list != null) @@ -1362,7 +1364,7 @@ private static TSource MinMaxImpl( Func lesser) { CheckNotNull(source, "source"); - Debug.Assert(lesser != null); + MiscellaneousUtils.Assert(lesser != null); return source.Aggregate((a, item) => lesser(a, item) ? a : item); } @@ -1376,7 +1378,7 @@ private static TSource MinMaxImpl( TSource? seed, Func lesser) where TSource : struct { CheckNotNull(source, "source"); - Debug.Assert(lesser != null); + MiscellaneousUtils.Assert(lesser != null); return source.Aggregate(seed, (a, item) => lesser(a, item) ? a : item); // == MinMaxImpl(Repeat(null, 1).Concat(source), lesser); @@ -1440,7 +1442,7 @@ public static TResult Max( private static IEnumerable Renumerable(this IEnumerator e) { - Debug.Assert(e != null); + MiscellaneousUtils.Assert(e != null); do { diff --git a/Src/Newtonsoft.Json/Utilities/MethodBinder.cs b/Src/Newtonsoft.Json/Utilities/MethodBinder.cs index 17d5c6278..541cfe5d5 100644 --- a/Src/Newtonsoft.Json/Utilities/MethodBinder.cs +++ b/Src/Newtonsoft.Json/Utilities/MethodBinder.cs @@ -126,7 +126,7 @@ private static bool FilterParameters(ParameterInfo[] parameters, IList typ } // check if the last parameter is ParamArray - Type paramArrayType = null; + Type? paramArrayType = null; if (enableParamArray) { @@ -211,7 +211,7 @@ public int Compare(ParameterInfo[] parameters1, ParameterInfo[] parameters2) return 1; } - Type paramArrayType1 = null, paramArrayType2 = null; + Type? paramArrayType1 = null, paramArrayType2 = null; if (_enableParamArray) { diff --git a/Src/Newtonsoft.Json/Utilities/MethodCall.cs b/Src/Newtonsoft.Json/Utilities/MethodCall.cs index 8b16e28f9..745a20712 100644 --- a/Src/Newtonsoft.Json/Utilities/MethodCall.cs +++ b/Src/Newtonsoft.Json/Utilities/MethodCall.cs @@ -25,5 +25,5 @@ namespace Newtonsoft.Json.Utilities { - internal delegate TResult MethodCall(T target, params object[] args); + internal delegate TResult MethodCall(T target, params object?[] args); } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs index 399e500d9..c469ce647 100644 --- a/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/MiscellaneousUtils.cs @@ -31,6 +31,8 @@ using System.Text; using System.Globalization; using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace Newtonsoft.Json.Utilities { @@ -38,7 +40,13 @@ namespace Newtonsoft.Json.Utilities internal static class MiscellaneousUtils { - public static bool ValueEquals(object objA, object objB) + [Conditional("DEBUG")] + public static void Assert([DoesNotReturnIf(false)] bool condition, string? message = null) + { + Debug.Assert(condition, message); + } + + public static bool ValueEquals(object? objA, object? objB) { if (objA == objB) { @@ -77,14 +85,14 @@ public static ArgumentOutOfRangeException CreateArgumentOutOfRangeException(stri return new ArgumentOutOfRangeException(paramName, newMessage); } - public static string ToString(object value) + public static string ToString(object? value) { if (value == null) { return "{null}"; } - return (value is string s) ? @"""" + s + @"""" : value.ToString(); + return (value is string s) ? @"""" + s + @"""" : value!.ToString()!; } public static int ByteArrayCompare(byte[] a1, byte[] a2) @@ -107,9 +115,9 @@ public static int ByteArrayCompare(byte[] a1, byte[] a2) return 0; } - public static string GetPrefix(string qualifiedName) + public static string? GetPrefix(string qualifiedName) { - GetQualifiedNameParts(qualifiedName, out string prefix, out _); + GetQualifiedNameParts(qualifiedName, out string? prefix, out _); return prefix; } @@ -121,9 +129,9 @@ public static string GetLocalName(string qualifiedName) return localName; } - public static void GetQualifiedNameParts(string qualifiedName, out string prefix, out string localName) + public static void GetQualifiedNameParts(string qualifiedName, out string? prefix, out string localName) { - int colonPosition = qualifiedName.IndexOf(':'); + int colonPosition = StringUtils.IndexOf(qualifiedName, ':'); if ((colonPosition == -1 || colonPosition == 0) || (qualifiedName.Length - 1) == colonPosition) { @@ -140,9 +148,10 @@ public static void GetQualifiedNameParts(string qualifiedName, out string prefix internal static RegexOptions GetRegexOptions(string optionsText) { RegexOptions options = RegexOptions.None; - foreach (char c in optionsText) + + for (int i = 0; i < optionsText.Length; i++) { - switch (c) + switch (optionsText[i]) { case 'i': options |= RegexOptions.IgnoreCase; diff --git a/Src/Newtonsoft.Json/Utilities/NullableAttributes.cs b/Src/Newtonsoft.Json/Utilities/NullableAttributes.cs new file mode 100644 index 000000000..5733cb801 --- /dev/null +++ b/Src/Newtonsoft.Json/Utilities/NullableAttributes.cs @@ -0,0 +1,78 @@ +#region License +// Copyright (c) 2007 James Newton-King +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +#if !HAVE_NULLABLE_ATTRIBUTES + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that an output will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true)] + internal sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class MaybeNullAttribute : Attribute + { } + + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class AllowNullAttribute : Attribute + { } + + /// + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal class DoesNotReturnIfAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => this.ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +} + +#endif \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs b/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs index 13d38f636..6b2d4ee24 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionDelegateFactory.cs @@ -36,7 +36,7 @@ namespace Newtonsoft.Json.Utilities { internal abstract class ReflectionDelegateFactory { - public Func CreateGet(MemberInfo memberInfo) + public Func CreateGet(MemberInfo memberInfo) { if (memberInfo is PropertyInfo propertyInfo) { @@ -57,7 +57,7 @@ public Func CreateGet(MemberInfo memberInfo) throw new Exception("Could not create getter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); } - public Action CreateSet(MemberInfo memberInfo) + public Action CreateSet(MemberInfo memberInfo) { if (memberInfo is PropertyInfo propertyInfo) { @@ -72,12 +72,12 @@ public Action CreateSet(MemberInfo memberInfo) throw new Exception("Could not create setter for {0}.".FormatWith(CultureInfo.InvariantCulture, memberInfo)); } - public abstract MethodCall CreateMethodCall(MethodBase method); + public abstract MethodCall CreateMethodCall(MethodBase method); public abstract ObjectConstructor CreateParameterizedConstructor(MethodBase method); public abstract Func CreateDefaultConstructor(Type type); - public abstract Func CreateGet(PropertyInfo propertyInfo); - public abstract Func CreateGet(FieldInfo fieldInfo); - public abstract Action CreateSet(FieldInfo fieldInfo); - public abstract Action CreateSet(PropertyInfo propertyInfo); + public abstract Func CreateGet(PropertyInfo propertyInfo); + public abstract Func CreateGet(FieldInfo fieldInfo); + public abstract Action CreateSet(FieldInfo fieldInfo); + public abstract Action CreateSet(PropertyInfo propertyInfo); } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionObject.cs b/Src/Newtonsoft.Json/Utilities/ReflectionObject.cs index 5eda2da0c..1463416db 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionObject.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionObject.cs @@ -39,37 +39,37 @@ namespace Newtonsoft.Json.Utilities { internal class ReflectionMember { - public Type MemberType { get; set; } - public Func Getter { get; set; } - public Action Setter { get; set; } + public Type? MemberType { get; set; } + public Func? Getter { get; set; } + public Action? Setter { get; set; } } internal class ReflectionObject { - public ObjectConstructor Creator { get; } + public ObjectConstructor? Creator { get; } public IDictionary Members { get; } - private ReflectionObject(ObjectConstructor creator) + private ReflectionObject(ObjectConstructor? creator) { Members = new Dictionary(); Creator = creator; } - public object GetValue(object target, string member) + public object? GetValue(object target, string member) { - Func getter = Members[member].Getter; + Func getter = Members[member].Getter!; return getter(target); } - public void SetValue(object target, string member, object value) + public void SetValue(object target, string member, object? value) { - Action setter = Members[member].Setter; + Action setter = Members[member].Setter!; setter(target, value); } public Type GetType(string member) { - return Members[member].MemberType; + return Members[member].MemberType!; } public static ReflectionObject Create(Type t, params string[] memberNames) @@ -77,11 +77,11 @@ public static ReflectionObject Create(Type t, params string[] memberNames) return Create(t, null, memberNames); } - public static ReflectionObject Create(Type t, MethodBase creator, params string[] memberNames) + public static ReflectionObject Create(Type t, MethodBase? creator, params string[] memberNames) { ReflectionDelegateFactory delegateFactory = JsonTypeReflector.ReflectionDelegateFactory; - ObjectConstructor creatorConstructor = null; + ObjectConstructor? creatorConstructor = null; if (creator != null) { creatorConstructor = delegateFactory.CreateParameterizedConstructor(creator); @@ -131,12 +131,12 @@ public static ReflectionObject Create(Type t, MethodBase creator, params string[ ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 0 && method.ReturnType != typeof(void)) { - MethodCall call = delegateFactory.CreateMethodCall(method); + MethodCall call = delegateFactory.CreateMethodCall(method); reflectionMember.Getter = target => call(target); } else if (parameters.Length == 1 && method.ReturnType == typeof(void)) { - MethodCall call = delegateFactory.CreateMethodCall(method); + MethodCall call = delegateFactory.CreateMethodCall(method); reflectionMember.Setter = (target, arg) => call(target, arg); } } diff --git a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs index c4ed506e5..f3d594244 100644 --- a/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs @@ -32,6 +32,8 @@ using System.Collections; using System.Globalization; using System.Text; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -96,7 +98,7 @@ public static bool IsVirtual(this PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); - MethodInfo m = propertyInfo.GetGetMethod(true); + MethodInfo? m = propertyInfo.GetGetMethod(true); if (m != null && m.IsVirtual) { return true; @@ -111,11 +113,11 @@ public static bool IsVirtual(this PropertyInfo propertyInfo) return false; } - public static MethodInfo GetBaseDefinition(this PropertyInfo propertyInfo) + public static MethodInfo? GetBaseDefinition(this PropertyInfo propertyInfo) { ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo)); - MethodInfo m = propertyInfo.GetGetMethod(true); + MethodInfo? m = propertyInfo.GetGetMethod(true); if (m != null) { return m.GetBaseDefinition(); @@ -126,11 +128,13 @@ public static MethodInfo GetBaseDefinition(this PropertyInfo propertyInfo) public static bool IsPublic(PropertyInfo property) { - if (property.GetGetMethod() != null && property.GetGetMethod().IsPublic) + var getMethod = property.GetGetMethod(); + if (getMethod != null && getMethod.IsPublic) { return true; } - if (property.GetSetMethod() != null && property.GetSetMethod().IsPublic) + var setMethod = property.GetSetMethod(); + if (setMethod != null && setMethod.IsPublic) { return true; } @@ -138,12 +142,12 @@ public static bool IsPublic(PropertyInfo property) return false; } - public static Type GetObjectType(object v) + public static Type? GetObjectType(object? v) { return v?.GetType(); } - public static string GetTypeName(Type t, TypeNameAssemblyFormatHandling assemblyFormat, ISerializationBinder binder) + public static string GetTypeName(Type t, TypeNameAssemblyFormatHandling assemblyFormat, ISerializationBinder? binder) { string fullyQualifiedTypeName = GetFullyQualifiedTypeName(t, binder); @@ -158,11 +162,11 @@ public static string GetTypeName(Type t, TypeNameAssemblyFormatHandling assembly } } - private static string GetFullyQualifiedTypeName(Type t, ISerializationBinder binder) + private static string GetFullyQualifiedTypeName(Type t, ISerializationBinder? binder) { if (binder != null) { - binder.BindToName(t, out string assemblyName, out string typeName); + binder.BindToName(t, out string? assemblyName, out string? typeName); #if (NET20 || NET35) // for older SerializationBinder implementations that didn't have BindToName if (assemblyName == null & typeName == null) @@ -173,7 +177,7 @@ private static string GetFullyQualifiedTypeName(Type t, ISerializationBinder bin return typeName + (assemblyName == null ? "" : ", " + assemblyName); } - return t.AssemblyQualifiedName; + return t.AssemblyQualifiedName!; } private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) @@ -183,19 +187,30 @@ private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) // loop through the type name and filter out qualified assembly details from nested type names bool writingAssemblyName = false; bool skippingAssemblyDetails = false; + bool followBrackets = false; for (int i = 0; i < fullyQualifiedTypeName.Length; i++) { char current = fullyQualifiedTypeName[i]; switch (current) { case '[': + writingAssemblyName = false; + skippingAssemblyDetails = false; + followBrackets = true; + builder.Append(current); + break; case ']': writingAssemblyName = false; skippingAssemblyDetails = false; + followBrackets = false; builder.Append(current); break; case ',': - if (!writingAssemblyName) + if (followBrackets) + { + builder.Append(current); + } + else if (!writingAssemblyName) { writingAssemblyName = true; builder.Append(current); @@ -206,6 +221,7 @@ private static string RemoveAssemblyDetails(string fullyQualifiedTypeName) } break; default: + followBrackets = false; if (!skippingAssemblyDetails) { builder.Append(current); @@ -229,12 +245,12 @@ public static bool HasDefaultConstructor(Type t, bool nonPublic) return (GetDefaultConstructor(t, nonPublic) != null); } - public static ConstructorInfo GetDefaultConstructor(Type t) + public static ConstructorInfo? GetDefaultConstructor(Type t) { return GetDefaultConstructor(t, false); } - public static ConstructorInfo GetDefaultConstructor(Type t, bool nonPublic) + public static ConstructorInfo? GetDefaultConstructor(Type t, bool nonPublic) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; if (nonPublic) @@ -267,14 +283,14 @@ public static bool IsNullableType(Type t) public static Type EnsureNotNullableType(Type t) { return (IsNullableType(t)) - ? Nullable.GetUnderlyingType(t) + ? Nullable.GetUnderlyingType(t)! : t; } public static Type EnsureNotByRefType(Type t) { return (t.IsByRef && t.HasElementType) - ? t.GetElementType() + ? t.GetElementType()! : t; } @@ -294,7 +310,7 @@ public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceD return ImplementsGenericDefinition(type, genericInterfaceDefinition, out _); } - public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition, out Type implementingType) + public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition, [NotNullWhen(true)]out Type? implementingType) { ValidationUtils.ArgumentNotNull(type, nameof(type)); ValidationUtils.ArgumentNotNull(genericInterfaceDefinition, nameof(genericInterfaceDefinition)); @@ -341,7 +357,7 @@ public static bool InheritsGenericDefinition(Type type, Type genericClassDefinit return InheritsGenericDefinition(type, genericClassDefinition, out _); } - public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition, out Type implementingType) + public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition, out Type? implementingType) { ValidationUtils.ArgumentNotNull(type, nameof(type)); ValidationUtils.ArgumentNotNull(genericClassDefinition, nameof(genericClassDefinition)); @@ -354,8 +370,9 @@ public static bool InheritsGenericDefinition(Type type, Type genericClassDefinit return InheritsGenericDefinitionInternal(type, genericClassDefinition, out implementingType); } - private static bool InheritsGenericDefinitionInternal(Type currentType, Type genericClassDefinition, out Type implementingType) + private static bool InheritsGenericDefinitionInternal(Type type, Type genericClassDefinition, out Type? implementingType) { + Type? currentType = type; do { if (currentType.IsGenericType() && genericClassDefinition == currentType.GetGenericTypeDefinition()) @@ -377,7 +394,7 @@ private static bool InheritsGenericDefinitionInternal(Type currentType, Type gen /// /// The type. /// The type of the typed collection's items. - public static Type GetCollectionItemType(Type type) + public static Type? GetCollectionItemType(Type type) { ValidationUtils.ArgumentNotNull(type, nameof(type)); @@ -385,14 +402,14 @@ public static Type GetCollectionItemType(Type type) { return type.GetElementType(); } - if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out Type genericListType)) + if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out Type? genericListType)) { - if (genericListType.IsGenericTypeDefinition()) + if (genericListType!.IsGenericTypeDefinition()) { throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type)); } - return genericListType.GetGenericArguments()[0]; + return genericListType!.GetGenericArguments()[0]; } if (typeof(IEnumerable).IsAssignableFrom(type)) { @@ -402,18 +419,18 @@ public static Type GetCollectionItemType(Type type) throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type)); } - public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType) + public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type? keyType, out Type? valueType) { ValidationUtils.ArgumentNotNull(dictionaryType, nameof(dictionaryType)); - if (ImplementsGenericDefinition(dictionaryType, typeof(IDictionary<,>), out Type genericDictionaryType)) + if (ImplementsGenericDefinition(dictionaryType, typeof(IDictionary<,>), out Type? genericDictionaryType)) { - if (genericDictionaryType.IsGenericTypeDefinition()) + if (genericDictionaryType!.IsGenericTypeDefinition()) { throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType)); } - Type[] dictionaryGenericArguments = genericDictionaryType.GetGenericArguments(); + Type[] dictionaryGenericArguments = genericDictionaryType!.GetGenericArguments(); keyType = dictionaryGenericArguments[0]; valueType = dictionaryGenericArguments[1]; @@ -445,7 +462,7 @@ public static Type GetMemberUnderlyingType(MemberInfo member) case MemberTypes.Property: return ((PropertyInfo)member).PropertyType; case MemberTypes.Event: - return ((EventInfo)member).EventHandlerType; + return ((EventInfo)member).EventHandlerType!; case MemberTypes.Method: return ((MethodInfo)member).ReturnType; default: @@ -493,7 +510,7 @@ public static bool IsIndexedProperty(PropertyInfo property) /// The member. /// The target object. /// The member's value on the object. - public static object GetMemberValue(MemberInfo member, object target) + public static object? GetMemberValue(MemberInfo member, object target) { ValidationUtils.ArgumentNotNull(member, nameof(member)); ValidationUtils.ArgumentNotNull(target, nameof(target)); @@ -522,7 +539,7 @@ public static object GetMemberValue(MemberInfo member, object target) /// The member. /// The target. /// The value. - public static void SetMemberValue(MemberInfo member, object target, object value) + public static void SetMemberValue(MemberInfo member, object target, object? value) { ValidationUtils.ArgumentNotNull(member, nameof(member)); ValidationUtils.ArgumentNotNull(target, nameof(target)); @@ -697,7 +714,7 @@ private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags return false; } - Type declaringType = propertyInfo.DeclaringType; + Type declaringType = propertyInfo.DeclaringType!; if (!declaringType.IsGenericType()) { return false; @@ -721,12 +738,12 @@ private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags return true; } - public static T GetAttribute(object attributeProvider) where T : Attribute + public static T? GetAttribute(object attributeProvider) where T : Attribute { return GetAttribute(attributeProvider, true); } - public static T GetAttribute(object attributeProvider, bool inherit) where T : Attribute + public static T? GetAttribute(object attributeProvider, bool inherit) where T : Attribute { T[] attributes = GetAttributes(attributeProvider, inherit); @@ -746,7 +763,7 @@ public static T[] GetAttributes(object attributeProvider, bool inherit) where return a.Cast().ToArray(); } - public static Attribute[] GetAttributes(object attributeProvider, Type attributeType, bool inherit) + public static Attribute[] GetAttributes(object attributeProvider, Type? attributeType, bool inherit) { ValidationUtils.ArgumentNotNull(attributeProvider, nameof(attributeProvider)); @@ -797,7 +814,7 @@ public static T[] GetAttributes(object attributeProvider, bool inherit) where return GetAttributes(attributeProvider, typeof(T), inherit).Cast().ToArray(); } - public static Attribute[] GetAttributes(object provider, Type attributeType, bool inherit) + public static Attribute[] GetAttributes(object provider, Type? attributeType, bool inherit) { switch (provider) { @@ -819,12 +836,12 @@ public static Attribute[] GetAttributes(object provider, Type attributeType, boo } #endif - public static StructMultiKey SplitFullyQualifiedTypeName(string fullyQualifiedTypeName) + public static StructMultiKey SplitFullyQualifiedTypeName(string fullyQualifiedTypeName) { int? assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName); string typeName; - string assemblyName; + string? assemblyName; if (assemblyDelimiterIndex != null) { @@ -837,7 +854,7 @@ public static StructMultiKey SplitFullyQualifiedTypeName(string assemblyName = null; } - return new StructMultiKey(assemblyName, typeName); + return new StructMultiKey(assemblyName, typeName); } private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName) @@ -868,7 +885,7 @@ public static StructMultiKey SplitFullyQualifiedTypeName(string return null; } - public static MemberInfo GetMemberInfoFromType(Type targetType, MemberInfo memberInfo) + public static MemberInfo? GetMemberInfoFromType(Type targetType, MemberInfo memberInfo) { const BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; @@ -900,8 +917,10 @@ public static IEnumerable GetFields(Type targetType, BindingFlags bin } #if !PORTABLE - private static void GetChildPrivateFields(IList initialFields, Type targetType, BindingFlags bindingAttr) + private static void GetChildPrivateFields(IList initialFields, Type type, BindingFlags bindingAttr) { + Type? targetType = type; + // fix weirdness with private FieldInfos only being returned for the current Type // find base type fields and add them to result if ((bindingAttr & BindingFlags.NonPublic) != 0) @@ -944,7 +963,7 @@ public static IEnumerable GetProperties(Type targetType, BindingFl PropertyInfo member = propertyInfos[i]; if (member.DeclaringType != targetType) { - PropertyInfo declaredMember = (PropertyInfo)GetMemberInfoFromType(member.DeclaringType, member); + PropertyInfo declaredMember = (PropertyInfo)GetMemberInfoFromType(member.DeclaringType!, member)!; propertyInfos[i] = declaredMember; } } @@ -959,13 +978,14 @@ public static BindingFlags RemoveFlag(this BindingFlags bindingAttr, BindingFlag : bindingAttr; } - private static void GetChildPrivateProperties(IList initialProperties, Type targetType, BindingFlags bindingAttr) + private static void GetChildPrivateProperties(IList initialProperties, Type type, BindingFlags bindingAttr) { // fix weirdness with private PropertyInfos only being returned for the current Type // find base type properties and add them to result // also find base properties that have been hidden by subtype properties with the same name + Type? targetType = type; while ((targetType = targetType.BaseType()) != null) { foreach (PropertyInfo propertyInfo in targetType.GetProperties(bindingAttr)) @@ -1009,11 +1029,11 @@ private static void GetChildPrivateProperties(IList initialPropert } else { - Type subTypePropertyDeclaringType = subTypeProperty.GetBaseDefinition()?.DeclaringType ?? subTypeProperty.DeclaringType; + Type subTypePropertyDeclaringType = subTypeProperty.GetBaseDefinition()?.DeclaringType ?? subTypeProperty.DeclaringType!; int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name && p.IsVirtual() - && (p.GetBaseDefinition()?.DeclaringType ?? p.DeclaringType).IsAssignableFrom(subTypePropertyDeclaringType)); + && (p.GetBaseDefinition()?.DeclaringType ?? p.DeclaringType!).IsAssignableFrom(subTypePropertyDeclaringType)); // don't add a virtual property that has an override if (index == -1) @@ -1038,7 +1058,7 @@ public static bool IsMethodOverridden(Type currentType, Type methodDeclaringType return isMethodOverriden; } - public static object GetDefaultValue(Type type) + public static object? GetDefaultValue(Type type) { if (!type.IsValueType()) { diff --git a/Src/Newtonsoft.Json/Utilities/StringBuffer.cs b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs index 8c9dcf47d..bc62f825c 100644 --- a/Src/Newtonsoft.Json/Utilities/StringBuffer.cs +++ b/Src/Newtonsoft.Json/Utilities/StringBuffer.cs @@ -32,7 +32,7 @@ namespace Newtonsoft.Json.Utilities /// internal struct StringBuffer { - private char[] _buffer; + private char[]? _buffer; private int _position; public int Position @@ -43,7 +43,7 @@ public int Position public bool IsEmpty => _buffer == null; - public StringBuffer(IArrayPool bufferPool, int initalSize) : this(BufferUtils.RentBuffer(bufferPool, initalSize)) + public StringBuffer(IArrayPool? bufferPool, int initalSize) : this(BufferUtils.RentBuffer(bufferPool, initalSize)) { } @@ -53,21 +53,21 @@ private StringBuffer(char[] buffer) _position = 0; } - public void Append(IArrayPool bufferPool, char value) + public void Append(IArrayPool? bufferPool, char value) { // test if the buffer array is large enough to take the value - if (_position == _buffer.Length) + if (_position == _buffer!.Length) { EnsureSize(bufferPool, 1); } // set value and increment poisition - _buffer[_position++] = value; + _buffer![_position++] = value; } - public void Append(IArrayPool bufferPool, char[] buffer, int startIndex, int count) + public void Append(IArrayPool? bufferPool, char[] buffer, int startIndex, int count) { - if (_position + count >= _buffer.Length) + if (_position + count >= _buffer!.Length) { EnsureSize(bufferPool, count); } @@ -77,7 +77,7 @@ public void Append(IArrayPool bufferPool, char[] buffer, int startIndex, i _position += count; } - public void Clear(IArrayPool bufferPool) + public void Clear(IArrayPool? bufferPool) { if (_buffer != null) { @@ -87,7 +87,7 @@ public void Clear(IArrayPool bufferPool) _position = 0; } - private void EnsureSize(IArrayPool bufferPool, int appendLength) + private void EnsureSize(IArrayPool? bufferPool, int appendLength) { char[] newBuffer = BufferUtils.RentBuffer(bufferPool, (_position + appendLength) * 2); @@ -107,10 +107,10 @@ public override string ToString() public string ToString(int start, int length) { - // TODO: validation + MiscellaneousUtils.Assert(_buffer != null); return new string(_buffer, start, length); } - public char[] InternalBuffer => _buffer; + public char[]? InternalBuffer => _buffer; } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Utilities/StringUtils.cs b/Src/Newtonsoft.Json/Utilities/StringUtils.cs index 049c70a74..ad7637895 100644 --- a/Src/Newtonsoft.Json/Utilities/StringUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/StringUtils.cs @@ -28,6 +28,7 @@ using System.IO; using System.Text; using System.Globalization; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -45,27 +46,32 @@ internal static class StringUtils public const char LineFeed = '\n'; public const char Tab = '\t'; - public static string FormatWith(this string format, IFormatProvider provider, object arg0) + public static bool IsNullOrEmpty([NotNullWhen(false)] string? value) { - return format.FormatWith(provider, new[] { arg0 }); + return string.IsNullOrEmpty(value); } - public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0) { - return format.FormatWith(provider, new[] { arg0, arg1 }); + return format.FormatWith(provider, new object?[] { arg0 }); } - public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1, object arg2) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0, object? arg1) { - return format.FormatWith(provider, new[] { arg0, arg1, arg2 }); + return format.FormatWith(provider, new object?[] { arg0, arg1 }); } - public static string FormatWith(this string format, IFormatProvider provider, object arg0, object arg1, object arg2, object arg3) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0, object? arg1, object? arg2) { - return format.FormatWith(provider, new[] { arg0, arg1, arg2, arg3 }); + return format.FormatWith(provider, new object?[] { arg0, arg1, arg2 }); } - private static string FormatWith(this string format, IFormatProvider provider, params object[] args) + public static string FormatWith(this string format, IFormatProvider provider, object? arg0, object? arg1, object? arg2, object? arg3) + { + return format.FormatWith(provider, new object?[] { arg0, arg1, arg2, arg3 }); + } + + private static string FormatWith(this string format, IFormatProvider provider, params object?[] args) { // leave this a private to force code to use an explicit overload // avoids stack memory being reserved for the object array @@ -122,7 +128,7 @@ public static void ToCharAsUnicode(char c, char[] buffer) buffer[5] = MathUtils.IntToHex(c & '\x000f'); } - public static TSource ForgivingCaseSensitiveFind(this IEnumerable source, Func valueSelector, string testValue) + public static TSource? ForgivingCaseSensitiveFind(this IEnumerable source, Func valueSelector, string testValue) { if (source == null) { @@ -148,7 +154,7 @@ public static TSource ForgivingCaseSensitiveFind(this IEnumerable ToSeparatedCase(s, '_'); + + public static string ToKebabCase(string s) => ToSeparatedCase(s, '-'); + + private enum SeparatedCaseState { Start, Lower, @@ -205,43 +215,43 @@ internal enum SnakeCaseState NewWord } - public static string ToSnakeCase(string s) + private static string ToSeparatedCase(string s, char separator) { - if (string.IsNullOrEmpty(s)) + if (StringUtils.IsNullOrEmpty(s)) { return s; } StringBuilder sb = new StringBuilder(); - SnakeCaseState state = SnakeCaseState.Start; + SeparatedCaseState state = SeparatedCaseState.Start; for (int i = 0; i < s.Length; i++) { if (s[i] == ' ') { - if (state != SnakeCaseState.Start) + if (state != SeparatedCaseState.Start) { - state = SnakeCaseState.NewWord; + state = SeparatedCaseState.NewWord; } } else if (char.IsUpper(s[i])) { switch (state) { - case SnakeCaseState.Upper: + case SeparatedCaseState.Upper: bool hasNext = (i + 1 < s.Length); if (i > 0 && hasNext) { char nextChar = s[i + 1]; - if (!char.IsUpper(nextChar) && nextChar != '_') + if (!char.IsUpper(nextChar) && nextChar != separator) { - sb.Append('_'); + sb.Append(separator); } } break; - case SnakeCaseState.Lower: - case SnakeCaseState.NewWord: - sb.Append('_'); + case SeparatedCaseState.Lower: + case SeparatedCaseState.NewWord: + sb.Append(separator); break; } @@ -253,22 +263,22 @@ public static string ToSnakeCase(string s) #endif sb.Append(c); - state = SnakeCaseState.Upper; + state = SeparatedCaseState.Upper; } - else if (s[i] == '_') + else if (s[i] == separator) { - sb.Append('_'); - state = SnakeCaseState.Start; + sb.Append(separator); + state = SeparatedCaseState.Start; } else { - if (state == SnakeCaseState.NewWord) + if (state == SeparatedCaseState.NewWord) { - sb.Append('_'); + sb.Append(separator); } sb.Append(s[i]); - state = SnakeCaseState.Lower; + state = SeparatedCaseState.Lower; } } @@ -293,6 +303,24 @@ public static bool IsLowSurrogate(char c) #endif } + public static int IndexOf(string s, char c) + { +#if HAVE_INDEXOF_STRING_COMPARISON + return s.IndexOf(c, StringComparison.Ordinal); +#else + return s.IndexOf(c); +#endif + } + + public static string Replace(string s, string oldValue, string newValue) + { +#if HAVE_REPLACE_STRING_COMPARISON + return s.Replace(oldValue, newValue, StringComparison.Ordinal); +#else + return s.Replace(oldValue, newValue); +#endif + } + public static bool StartsWith(this string source, char value) { return (source.Length > 0 && source[0] == value); diff --git a/Src/Newtonsoft.Json/Utilities/StructMultiKey.cs b/Src/Newtonsoft.Json/Utilities/StructMultiKey.cs index 10428aaaf..a36d1d152 100644 --- a/Src/Newtonsoft.Json/Utilities/StructMultiKey.cs +++ b/Src/Newtonsoft.Json/Utilities/StructMultiKey.cs @@ -43,7 +43,7 @@ public override int GetHashCode() return (Value1?.GetHashCode() ?? 0) ^ (Value2?.GetHashCode() ?? 0); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (!(obj is StructMultiKey key)) { diff --git a/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs b/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs index 2e135f0ac..0413f22b0 100644 --- a/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs +++ b/Src/Newtonsoft.Json/Utilities/ThreadSafeStore.cs @@ -36,7 +36,7 @@ namespace Newtonsoft.Json.Utilities { - internal class ThreadSafeStore + internal class ThreadSafeStore where TKey : notnull { #if HAVE_CONCURRENT_DICTIONARY private readonly ConcurrentDictionary _concurrentStore; diff --git a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs index 646080814..934302d65 100644 --- a/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs +++ b/Src/Newtonsoft.Json/Utilities/TypeExtensions.cs @@ -26,6 +26,8 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if !HAVE_LINQ using Newtonsoft.Json.Utilities.LinqBridge; #else @@ -40,12 +42,12 @@ internal static class TypeExtensions #if !DOTNET private static readonly BindingFlags DefaultFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; - public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo) + public static MethodInfo? GetGetMethod(this PropertyInfo propertyInfo) { return propertyInfo.GetGetMethod(false); } - public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool nonPublic) + public static MethodInfo? GetGetMethod(this PropertyInfo propertyInfo, bool nonPublic) { MethodInfo getMethod = propertyInfo.GetMethod; if (getMethod != null && (getMethod.IsPublic || nonPublic)) @@ -56,12 +58,12 @@ public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool nonPu return null; } - public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo) + public static MethodInfo? GetSetMethod(this PropertyInfo propertyInfo) { return propertyInfo.GetSetMethod(false); } - public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo, bool nonPublic) + public static MethodInfo? GetSetMethod(this PropertyInfo propertyInfo, bool nonPublic) { MethodInfo setMethod = propertyInfo.SetMethod; if (setMethod != null && (setMethod.IsPublic || nonPublic)) @@ -85,7 +87,7 @@ public static bool IsAssignableFrom(this Type type, Type c) } #endif - public static bool IsInstanceOfType(this Type type, object o) + public static bool IsInstanceOfType(this Type type, object? o) { if (o == null) { @@ -169,7 +171,7 @@ public static bool IsGenericTypeDefinition(this Type type) #endif } - public static Type BaseType(this Type type) + public static Type? BaseType(this Type type) { #if HAVE_FULL_REFLECTION return type.BaseType; @@ -215,7 +217,7 @@ public static bool IsSealed(this Type type) } #if (PORTABLE40 || DOTNET || PORTABLE) - public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags, object placeholder1, Type propertyType, IList indexParameters, object placeholder2) + public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags, object? placeholder1, Type propertyType, IList indexParameters, object? placeholder2) { IEnumerable propertyInfos = type.GetProperties(bindingFlags); @@ -289,12 +291,12 @@ public static MethodInfo GetMethod(this Type type, IList parameterTypes) return type.GetMethod(null, parameterTypes); } - public static MethodInfo GetMethod(this Type type, string name, IList parameterTypes) + public static MethodInfo GetMethod(this Type type, string? name, IList parameterTypes) { return type.GetMethod(name, DefaultFlags, null, parameterTypes, null); } - public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags, object placeHolder1, IList parameterTypes, object placeHolder2) + public static MethodInfo GetMethod(this Type type, string? name, BindingFlags bindingFlags, object? placeHolder1, IList parameterTypes, object? placeHolder2) { return MethodBinder.SelectMethod(type.GetTypeInfo().DeclaredMethods.Where(m => (name == null || m.Name == name) && TestAccessibility(m, bindingFlags)), parameterTypes); } @@ -314,7 +316,7 @@ public static ConstructorInfo GetConstructor(this Type type, IList paramet return type.GetConstructor(DefaultFlags, null, parameterTypes, null); } - public static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, object placeholder1, IList parameterTypes, object placeholder2) + public static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, object? placeholder1, IList parameterTypes, object? placeholder2) { return MethodBinder.SelectMethod(type.GetConstructors(bindingFlags), parameterTypes); } @@ -338,12 +340,12 @@ public static MemberInfo[] GetMemberInternal(this Type type, string member, Memb TestAccessibility(m, bindingFlags)).ToArray(); } - public static FieldInfo GetField(this Type type, string member) + public static FieldInfo? GetField(this Type type, string member) { return type.GetField(member, DefaultFlags); } - public static FieldInfo GetField(this Type type, string member, BindingFlags bindingFlags) + public static FieldInfo? GetField(this Type type, string member, BindingFlags bindingFlags) { FieldInfo field = type.GetTypeInfo().GetDeclaredField(member); if (field == null || !TestAccessibility(field, bindingFlags)) @@ -378,7 +380,7 @@ private static bool ContainsMemberName(IEnumerable members, string n private static IList GetMembersRecursive(this TypeInfo type) { - TypeInfo t = type; + TypeInfo? t = type; List members = new List(); while (t != null) { @@ -397,7 +399,7 @@ private static IList GetMembersRecursive(this TypeInfo type) private static IList GetPropertiesRecursive(this TypeInfo type) { - TypeInfo t = type; + TypeInfo? t = type; List properties = new List(); while (t != null) { @@ -416,7 +418,7 @@ private static IList GetPropertiesRecursive(this TypeInfo type) private static IList GetFieldsRecursive(this TypeInfo type) { - TypeInfo t = type; + TypeInfo? t = type; List fields = new List(); while (t != null) { @@ -438,12 +440,12 @@ public static IEnumerable GetMethods(this Type type, BindingFlags bi return type.GetTypeInfo().DeclaredMethods; } - public static PropertyInfo GetProperty(this Type type, string name) + public static PropertyInfo? GetProperty(this Type type, string name) { return type.GetProperty(name, DefaultFlags); } - public static PropertyInfo GetProperty(this Type type, string name, BindingFlags bindingFlags) + public static PropertyInfo? GetProperty(this Type type, string name, BindingFlags bindingFlags) { PropertyInfo property = type.GetTypeInfo().GetDeclaredProperty(name); if (property == null || !TestAccessibility(property, bindingFlags)) @@ -576,9 +578,9 @@ public static bool IsPrimitive(this Type type) #endif } - public static bool AssignableToTypeName(this Type type, string fullTypeName, bool searchInterfaces, out Type match) + public static bool AssignableToTypeName(this Type type, string fullTypeName, bool searchInterfaces, [NotNullWhen(true)]out Type? match) { - Type current = type; + Type? current = type; while (current != null) { @@ -614,7 +616,7 @@ public static bool AssignableToTypeName(this Type type, string fullTypeName, boo public static bool ImplementInterface(this Type type, Type interfaceType) { - for (Type currentType = type; currentType != null; currentType = currentType.BaseType()) + for (Type? currentType = type; currentType != null; currentType = currentType.BaseType()) { IEnumerable interfaces = currentType.GetInterfaces(); foreach (Type i in interfaces) diff --git a/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs index 845ba3ea3..df17082f4 100644 --- a/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ValidationUtils.cs @@ -24,12 +24,14 @@ #endregion using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace Newtonsoft.Json.Utilities { internal static class ValidationUtils { - public static void ArgumentNotNull(object value, string parameterName) + public static void ArgumentNotNull([NotNull]object? value, string parameterName) { if (value == null) { diff --git a/Src/Newtonsoft.Json/packageIcon.png b/Src/Newtonsoft.Json/packageIcon.png new file mode 100644 index 000000000..10c06a5c4 Binary files /dev/null and b/Src/Newtonsoft.Json/packageIcon.png differ diff --git a/Src/global.json b/Src/global.json index 2be3e8661..18b4598f7 100644 --- a/Src/global.json +++ b/Src/global.json @@ -1,5 +1,6 @@ { "sdk": { - "version": "2.2.105" + "version": "6.0.400", + "rollForward": "latestFeature" } -} \ No newline at end of file +} diff --git a/azure-pipelines.yml b/azure-pipelines.yml index baffb3246..9ff4dd649 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,9 +3,28 @@ trigger: - release/* pool: - vmImage: 'VS2017-Win2016' + vmImage: 'windows-2022' steps: +- task: UseDotNet@2 + inputs: + version: '6.0.x' + +- task: UseDotNet@2 + inputs: + version: '2.1.x' + packageType: runtime + +- task: UseDotNet@2 + inputs: + version: '3.1.x' + packageType: runtime + +- task: UseDotNet@2 + inputs: + version: '5.0.x' + packageType: runtime + - powershell: | dotnet --info displayName: 'Dotnet installs' @@ -30,7 +49,9 @@ steps: write-host "Build number $buildNumber" -fore white $nugetPrerelease = if ($Env:SourceBranch.StartsWith("refs/heads/release/")) { $version.Prerelease } else { "build$($buildNumber.ToString("D6"))" } write-host "Prerelease $nugetPrerelease" -fore white - .\Build\runbuild.ps1 -properties @{"majorVersion"="$($version.Major).0"; "majorWithReleaseVersion"="$($version.Major).0.$($version.Release)"; "nugetPrerelease"=$nugetPrerelease; "zipFileName"="Json$($version.Major)0r$($version.Release).zip"; "signAssemblies"=$sign; "signKeyPath"=$keyPath; "treatWarningsAsErrors"=$true; "buildNuGet"=$true} + $assemblyVersion = if ($version.Assembly) { $version.Assembly } else { "$($version.Major).0.0.0" } + write-host "Assembly $assemblyVersion" -fore white + .\Build\runbuild.ps1 -properties @{"majorVersion"="$($version.Major).0"; "majorWithReleaseVersion"="$($version.Major).0.$($version.Release)"; "nugetPrerelease"=$nugetPrerelease; "assemblyVersion"=$assemblyVersion; "zipFileName"="Json$($version.Major)0r$($version.Release).zip"; "signAssemblies"=$sign; "signKeyPath"=$keyPath; "treatWarningsAsErrors"=$true; "buildNuGet"=$true; "ensureNetCliSdk"=$false} env: BuildId: $(Build.BuildId) SourceBranch: $(Build.SourceBranch)