Hi,
I was just wondering whether there is a reason for defaulting the ProcessDictionaryKeys and OverrideSpecifiedNames settings in the CamelCasePropertyNamesContractResolver class to true:
https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/CamelCasePropertyNamesContractResolver.cs#L49-L50
I recently discovered an issue in a messaging library that uses JSON.NET for json serialization/deserialization and was able to trace it to its use of the above class with the default options. The issue itself resulted in Dictionary
The decision to make these values true by default on the contract resolver seems unintuitive to me, as it means that serializing and then deserializing dictionaries does not get you back to where you started. Though I am not certain of the behaviour of OverrideSpecifiedNames, I imagine the same might be true when using custom serialization via JsonProperty attributes if deserialization then relies on a custom constructor.
Is there something I am missing?
Thanks,
Alex
To reproduce the issue:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace ConsoleApp
{
class Program
{
static T SerializeAndDeserialize<T>(T obj, JsonSerializerSettings settings)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj, settings), settings);
}
static void Main(string[] args)
{
var dict = new Dictionary<string, string> {{"Foo", "Bar"}};
var settingsWithDictKeysCamelCased = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var settingsWithDictKeysUnchanged = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
var result1 = SerializeAndDeserialize(dict, settingsWithDictKeysCamelCased);
var result2 = SerializeAndDeserialize(dict, settingsWithDictKeysUnchanged);
Console.WriteLine(string.Join(", ", result1.Select(kvp => $"{kvp.Key}: {kvp.Value}"))); // foo: Bar
Console.WriteLine(string.Join(", ", result2.Select(kvp => $"{kvp.Key}: {kvp.Value}"))); // Foo: Bar
Console.ReadLine();
}
}
}
I also am seeing this behavior where a public Dictionary<string, bool> Blah { get; }
keys are being changed and I've tried setting ProcessDictionaryKeys
to false
.
They're set to true because that has always been the default behavior of CamelCasePropertyNamesContractResolver
. I added naming strategies later and decided to make them behave differently, however I couldn't change the resolver for backwards compatibility reasons.
Most helpful comment
They're set to true because that has always been the default behavior of
CamelCasePropertyNamesContractResolver
. I added naming strategies later and decided to make them behave differently, however I couldn't change the resolver for backwards compatibility reasons.