diff --git a/Src/Newtonsoft.Json.Tests/Issues/Issue2444.cs b/Src/Newtonsoft.Json.Tests/Issues/Issue2444.cs new file mode 100644 index 00000000..4932d15f --- /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/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index d047029b..5bf7e2a6 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -768,9 +768,7 @@ namespace Newtonsoft.Json [DebuggerStepThrough] public static T? DeserializeObject(string value, params JsonConverter[] converters) { -#pragma warning disable CS8601 // Possible null reference assignment. - return (T)DeserializeObject(value, typeof(T), converters); -#pragma warning restore CS8601 // Possible null reference assignment. + return (T?)DeserializeObject(value, typeof(T), converters); } /// @@ -786,9 +784,7 @@ namespace Newtonsoft.Json [DebuggerStepThrough] public static T? DeserializeObject(string value, JsonSerializerSettings? settings) { -#pragma warning disable CS8601 // Possible null reference assignment. - return (T)DeserializeObject(value, typeof(T), settings); -#pragma warning restore CS8601 // Possible null reference assignment. + return (T?)DeserializeObject(value, typeof(T), settings); } /// diff --git a/Src/Newtonsoft.Json/JsonConverter.cs b/Src/Newtonsoft.Json/JsonConverter.cs index 6b8a1ca2..2c04a09d 100644 --- a/Src/Newtonsoft.Json/JsonConverter.cs +++ b/Src/Newtonsoft.Json/JsonConverter.cs @@ -94,9 +94,7 @@ namespace Newtonsoft.Json { throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } -#pragma warning disable CS8601 // Possible null reference assignment. - WriteJson(writer, (T)value, serializer); -#pragma warning restore CS8601 // Possible null reference assignment. + WriteJson(writer, (T?)value, serializer); } /// @@ -122,9 +120,7 @@ namespace Newtonsoft.Json { throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } -#pragma warning disable CS8601 // Possible null reference assignment. - return ReadJson(reader, objectType, existingIsNull ? default : (T)existingValue, !existingIsNull, serializer); -#pragma warning restore CS8601 // Possible null reference assignment. + return ReadJson(reader, objectType, existingIsNull ? default : (T?)existingValue, !existingIsNull, serializer); } /// diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 8242f7f9..79aa9124 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -1931,9 +1931,7 @@ namespace Newtonsoft.Json.Linq /// The new object created from the JSON value. public T? ToObject() { -#pragma warning disable CS8601 // Possible null reference assignment. - return (T)ToObject(typeof(T)); -#pragma warning restore CS8601 // Possible null reference assignment. + return (T?)ToObject(typeof(T)); } /// @@ -2066,9 +2064,7 @@ namespace Newtonsoft.Json.Linq /// The new object created from the JSON value. public T? ToObject(JsonSerializer jsonSerializer) { -#pragma warning disable CS8601 // Possible null reference assignment. - return (T)ToObject(typeof(T), jsonSerializer); -#pragma warning restore CS8601 // Possible null reference assignment. + return (T?)ToObject(typeof(T), jsonSerializer); } /// diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index c54480b4..e79565a4 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -958,7 +958,11 @@ namespace Newtonsoft.Json.Serialization { 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)) { @@ -1387,7 +1391,7 @@ namespace Newtonsoft.Json.Serialization { 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 @@ -1396,12 +1400,14 @@ namespace Newtonsoft.Json.Serialization { 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; } }