You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
4.6 KiB

  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Collections.Generic;
  27. using System.Globalization;
  28. using Newtonsoft.Json.Utilities;
  29. namespace Newtonsoft.Json.Serialization
  30. {
  31. internal readonly struct ResolverContractKey : IEquatable<ResolverContractKey>
  32. {
  33. private readonly Type _resolverType;
  34. private readonly Type _contractType;
  35. public ResolverContractKey(Type resolverType, Type contractType)
  36. {
  37. _resolverType = resolverType;
  38. _contractType = contractType;
  39. }
  40. public override int GetHashCode()
  41. {
  42. return _resolverType.GetHashCode() ^ _contractType.GetHashCode();
  43. }
  44. public override bool Equals(object obj)
  45. {
  46. if (!(obj is ResolverContractKey))
  47. {
  48. return false;
  49. }
  50. return Equals((ResolverContractKey)obj);
  51. }
  52. public bool Equals(ResolverContractKey other)
  53. {
  54. return (_resolverType == other._resolverType && _contractType == other._contractType);
  55. }
  56. }
  57. /// <summary>
  58. /// Resolves member mappings for a type, camel casing property names.
  59. /// </summary>
  60. internal class CamelCasePropertyNamesContractResolver : DefaultContractResolver
  61. {
  62. private static readonly object TypeContractCacheLock = new object();
  63. private static readonly PropertyNameTable NameTable = new PropertyNameTable();
  64. private static Dictionary<ResolverContractKey, JsonContract> _contractCache;
  65. /// <summary>
  66. /// Initializes a new instance of the <see cref="CamelCasePropertyNamesContractResolver"/> class.
  67. /// </summary>
  68. public CamelCasePropertyNamesContractResolver()
  69. {
  70. NamingStrategy = new CamelCaseNamingStrategy
  71. {
  72. ProcessDictionaryKeys = true,
  73. OverrideSpecifiedNames = true
  74. };
  75. }
  76. /// <summary>
  77. /// Resolves the contract for a given type.
  78. /// </summary>
  79. /// <param name="type">The type to resolve a contract for.</param>
  80. /// <returns>The contract for a given type.</returns>
  81. public override JsonContract ResolveContract(Type type)
  82. {
  83. if (type == null)
  84. {
  85. throw new ArgumentNullException(nameof(type));
  86. }
  87. // for backwards compadibility the CamelCasePropertyNamesContractResolver shares contracts between instances
  88. JsonContract contract;
  89. ResolverContractKey key = new ResolverContractKey(GetType(), type);
  90. Dictionary<ResolverContractKey, JsonContract> cache = _contractCache;
  91. if (cache == null || !cache.TryGetValue(key, out contract))
  92. {
  93. contract = CreateContract(type);
  94. // avoid the possibility of modifying the cache dictionary while another thread is accessing it
  95. lock (TypeContractCacheLock)
  96. {
  97. cache = _contractCache;
  98. Dictionary<ResolverContractKey, JsonContract> updatedCache = (cache != null)
  99. ? new Dictionary<ResolverContractKey, JsonContract>(cache)
  100. : new Dictionary<ResolverContractKey, JsonContract>();
  101. updatedCache[key] = contract;
  102. _contractCache = updatedCache;
  103. }
  104. }
  105. return contract;
  106. }
  107. internal override PropertyNameTable GetNameTable()
  108. {
  109. return NameTable;
  110. }
  111. }
  112. }