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.

318 lines
13 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.Collections.ObjectModel;
  28. using System.ComponentModel;
  29. using System.Globalization;
  30. using System.Reflection;
  31. using Newtonsoft.Json.Utilities;
  32. using System.Collections;
  33. #if NET20
  34. using Newtonsoft.Json.Utilities.LinqBridge;
  35. #else
  36. using System.Linq;
  37. #endif
  38. namespace Newtonsoft.Json.Serialization
  39. {
  40. /// <summary>
  41. /// Contract details for a <see cref="System.Type"/> used by the <see cref="JsonSerializer"/>.
  42. /// </summary>
  43. internal class JsonArrayContract : JsonContainerContract
  44. {
  45. /// <summary>
  46. /// Gets the <see cref="System.Type"/> of the collection items.
  47. /// </summary>
  48. /// <value>The <see cref="System.Type"/> of the collection items.</value>
  49. public Type CollectionItemType { get; }
  50. /// <summary>
  51. /// Gets a value indicating whether the collection type is a multidimensional array.
  52. /// </summary>
  53. /// <value><c>true</c> if the collection type is a multidimensional array; otherwise, <c>false</c>.</value>
  54. public bool IsMultidimensionalArray { get; }
  55. private readonly Type _genericCollectionDefinitionType;
  56. private Type _genericWrapperType;
  57. private ObjectConstructor<object> _genericWrapperCreator;
  58. private Func<object> _genericTemporaryCollectionCreator;
  59. internal bool IsArray { get; }
  60. internal bool ShouldCreateWrapper { get; }
  61. internal bool CanDeserialize { get; private set; }
  62. private readonly ConstructorInfo _parameterizedConstructor;
  63. private ObjectConstructor<object> _parameterizedCreator;
  64. private ObjectConstructor<object> _overrideCreator;
  65. internal ObjectConstructor<object> ParameterizedCreator
  66. {
  67. get
  68. {
  69. if (_parameterizedCreator == null)
  70. {
  71. _parameterizedCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(_parameterizedConstructor);
  72. }
  73. return _parameterizedCreator;
  74. }
  75. }
  76. /// <summary>
  77. /// Gets or sets the function used to create the object. When set this function will override <see cref="JsonContract.DefaultCreator"/>.
  78. /// </summary>
  79. /// <value>The function used to create the object.</value>
  80. public ObjectConstructor<object> OverrideCreator
  81. {
  82. get => _overrideCreator;
  83. set
  84. {
  85. _overrideCreator = value;
  86. // hacky
  87. CanDeserialize = true;
  88. }
  89. }
  90. /// <summary>
  91. /// Gets a value indicating whether the creator has a parameter with the collection values.
  92. /// </summary>
  93. /// <value><c>true</c> if the creator has a parameter with the collection values; otherwise, <c>false</c>.</value>
  94. public bool HasParameterizedCreator { get; set; }
  95. internal bool HasParameterizedCreatorInternal => (HasParameterizedCreator || _parameterizedCreator != null || _parameterizedConstructor != null);
  96. /// <summary>
  97. /// Initializes a new instance of the <see cref="JsonArrayContract"/> class.
  98. /// </summary>
  99. /// <param name="underlyingType">The underlying type for the contract.</param>
  100. public JsonArrayContract(Type underlyingType)
  101. : base(underlyingType)
  102. {
  103. ContractType = JsonContractType.Array;
  104. IsArray = CreatedType.IsArray;
  105. bool canDeserialize;
  106. Type tempCollectionType;
  107. if (IsArray)
  108. {
  109. CollectionItemType = ReflectionUtils.GetCollectionItemType(UnderlyingType);
  110. IsReadOnlyOrFixedSize = true;
  111. _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType);
  112. canDeserialize = true;
  113. IsMultidimensionalArray = (IsArray && UnderlyingType.GetArrayRank() > 1);
  114. }
  115. else if (typeof(IList).IsAssignableFrom(underlyingType))
  116. {
  117. if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType))
  118. {
  119. CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0];
  120. }
  121. else
  122. {
  123. CollectionItemType = ReflectionUtils.GetCollectionItemType(underlyingType);
  124. }
  125. if (underlyingType == typeof(IList))
  126. {
  127. CreatedType = typeof(List<object>);
  128. }
  129. if (CollectionItemType != null)
  130. {
  131. _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
  132. }
  133. IsReadOnlyOrFixedSize = ReflectionUtils.InheritsGenericDefinition(underlyingType, typeof(ReadOnlyCollection<>));
  134. canDeserialize = true;
  135. }
  136. else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(ICollection<>), out _genericCollectionDefinitionType))
  137. {
  138. CollectionItemType = _genericCollectionDefinitionType.GetGenericArguments()[0];
  139. if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(ICollection<>))
  140. || ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IList<>)))
  141. {
  142. CreatedType = typeof(List<>).MakeGenericType(CollectionItemType);
  143. }
  144. #if !NET20
  145. if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(ISet<>)))
  146. {
  147. CreatedType = typeof(HashSet<>).MakeGenericType(CollectionItemType);
  148. }
  149. #endif
  150. _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
  151. canDeserialize = true;
  152. ShouldCreateWrapper = true;
  153. }
  154. #if NETSTD
  155. else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>), out tempCollectionType))
  156. {
  157. CollectionItemType = tempCollectionType.GetGenericArguments()[0];
  158. if (ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyCollection<>))
  159. || ReflectionUtils.IsGenericDefinition(underlyingType, typeof(IReadOnlyList<>)))
  160. {
  161. CreatedType = typeof(ReadOnlyCollection<>).MakeGenericType(CollectionItemType);
  162. }
  163. _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType);
  164. _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(CreatedType, CollectionItemType);
  165. #if !NET20
  166. StoreFSharpListCreatorIfNecessary(underlyingType);
  167. #endif
  168. IsReadOnlyOrFixedSize = true;
  169. canDeserialize = HasParameterizedCreatorInternal;
  170. }
  171. #endif
  172. else if (ReflectionUtils.ImplementsGenericDefinition(underlyingType, typeof(IEnumerable<>), out tempCollectionType))
  173. {
  174. CollectionItemType = tempCollectionType.GetGenericArguments()[0];
  175. if (ReflectionUtils.IsGenericDefinition(UnderlyingType, typeof(IEnumerable<>)))
  176. {
  177. CreatedType = typeof(List<>).MakeGenericType(CollectionItemType);
  178. }
  179. _parameterizedConstructor = CollectionUtils.ResolveEnumerableCollectionConstructor(underlyingType, CollectionItemType);
  180. #if !NET20
  181. StoreFSharpListCreatorIfNecessary(underlyingType);
  182. #endif
  183. if (underlyingType.IsGenericType() && underlyingType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
  184. {
  185. _genericCollectionDefinitionType = tempCollectionType;
  186. IsReadOnlyOrFixedSize = false;
  187. ShouldCreateWrapper = false;
  188. canDeserialize = true;
  189. }
  190. else
  191. {
  192. _genericCollectionDefinitionType = typeof(List<>).MakeGenericType(CollectionItemType);
  193. IsReadOnlyOrFixedSize = true;
  194. ShouldCreateWrapper = true;
  195. canDeserialize = HasParameterizedCreatorInternal;
  196. }
  197. }
  198. else
  199. {
  200. // types that implement IEnumerable and nothing else
  201. canDeserialize = false;
  202. ShouldCreateWrapper = true;
  203. }
  204. CanDeserialize = canDeserialize;
  205. #if (NET20 || NET35)
  206. if (CollectionItemType != null && ReflectionUtils.IsNullableType(CollectionItemType))
  207. {
  208. // bug in .NET 2.0 & 3.5 that List<Nullable<T>> throws an error when adding null via IList.Add(object)
  209. // wrapper will handle calling Add(T) instead
  210. if (ReflectionUtils.InheritsGenericDefinition(CreatedType, typeof(List<>), out tempCollectionType)
  211. || (IsArray && !IsMultidimensionalArray))
  212. {
  213. ShouldCreateWrapper = true;
  214. }
  215. }
  216. #endif
  217. if (ImmutableCollectionsUtils.TryBuildImmutableForArrayContract(
  218. underlyingType,
  219. CollectionItemType,
  220. out Type immutableCreatedType,
  221. out ObjectConstructor<object> immutableParameterizedCreator))
  222. {
  223. CreatedType = immutableCreatedType;
  224. _parameterizedCreator = immutableParameterizedCreator;
  225. IsReadOnlyOrFixedSize = true;
  226. CanDeserialize = true;
  227. }
  228. }
  229. internal IWrappedCollection CreateWrapper(object list)
  230. {
  231. if (_genericWrapperCreator == null)
  232. {
  233. _genericWrapperType = typeof(CollectionWrapper<>).MakeGenericType(CollectionItemType);
  234. Type constructorArgument;
  235. if (ReflectionUtils.InheritsGenericDefinition(_genericCollectionDefinitionType, typeof(List<>))
  236. || _genericCollectionDefinitionType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
  237. {
  238. constructorArgument = typeof(ICollection<>).MakeGenericType(CollectionItemType);
  239. }
  240. else
  241. {
  242. constructorArgument = _genericCollectionDefinitionType;
  243. }
  244. ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { constructorArgument });
  245. _genericWrapperCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateParameterizedConstructor(genericWrapperConstructor);
  246. }
  247. return (IWrappedCollection)_genericWrapperCreator(list);
  248. }
  249. internal IList CreateTemporaryCollection()
  250. {
  251. if (_genericTemporaryCollectionCreator == null)
  252. {
  253. // multidimensional array will also have array instances in it
  254. Type collectionItemType = (IsMultidimensionalArray || CollectionItemType == null)
  255. ? typeof(object)
  256. : CollectionItemType;
  257. Type temporaryListType = typeof(List<>).MakeGenericType(collectionItemType);
  258. _genericTemporaryCollectionCreator = JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(temporaryListType);
  259. }
  260. return (IList)_genericTemporaryCollectionCreator();
  261. }
  262. #if !NET20
  263. private void StoreFSharpListCreatorIfNecessary(Type underlyingType)
  264. {
  265. if (!HasParameterizedCreatorInternal && underlyingType.Name == FSharpUtils.FSharpListTypeName)
  266. {
  267. FSharpUtils.EnsureInitialized(underlyingType.Assembly());
  268. _parameterizedCreator = FSharpUtils.CreateSeq(CollectionItemType);
  269. }
  270. }
  271. #endif
  272. }
  273. }