2
// Copyright (c) 2007 James Newton-King
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
13
// The above copyright notice and this permission notice shall be
14
// included in all copies or substantial portions of the Software.
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.
27
using System.Collections;
28
using System.Collections.Generic;
29
using System.Collections.ObjectModel;
30
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
31
using System.ComponentModel;
34
using System.Diagnostics;
35
using System.Globalization;
36
using System.Reflection;
37
using System.Runtime.Serialization;
38
using Newtonsoft.Json.Linq;
39
using Newtonsoft.Json.Utilities;
41
using Newtonsoft.Json.Utilities.LinqBridge;
46
namespace Newtonsoft.Json.Serialization
48
internal class JsonSerializerInternalReader : JsonSerializerInternalBase
50
internal enum PropertyPresence
57
private JsonSerializerProxy _internalSerializer;
58
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
59
private JsonFormatterConverter _formatterConverter;
62
public JsonSerializerInternalReader(JsonSerializer serializer)
67
public void Populate(JsonReader reader, object target)
69
ValidationUtils.ArgumentNotNull(target, "target");
71
Type objectType = target.GetType();
73
JsonContract contract = Serializer.ContractResolver.ResolveContract(objectType);
75
if (reader.TokenType == JsonToken.None)
78
if (reader.TokenType == JsonToken.StartArray)
80
if (contract.ContractType == JsonContractType.Array)
81
PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, (JsonArrayContract) contract, null, null);
83
throw JsonSerializationException.Create(reader, "Cannot populate JSON array onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
85
else if (reader.TokenType == JsonToken.StartObject)
90
if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
93
id = (reader.Value != null) ? reader.Value.ToString() : null;
97
if (contract.ContractType == JsonContractType.Dictionary)
98
PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(target), reader, (JsonDictionaryContract) contract, null, id);
99
else if (contract.ContractType == JsonContractType.Object)
100
PopulateObject(target, reader, (JsonObjectContract) contract, null, id);
102
throw JsonSerializationException.Create(reader, "Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
106
throw JsonSerializationException.Create(reader, "Unexpected initial token '{0}' when populating object. Expected JSON object or array.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
110
private JsonContract GetContractSafe(Type type)
115
return Serializer.ContractResolver.ResolveContract(type);
118
public object Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
121
throw new ArgumentNullException("reader");
123
JsonContract contract = GetContractSafe(objectType);
127
JsonConverter converter = GetConverter(contract, null, null, null);
129
if (reader.TokenType == JsonToken.None && !ReadForType(reader, contract, converter != null))
131
if (contract != null && !contract.IsNullable)
132
throw JsonSerializationException.Create(reader, "No JSON content found and type '{0}' is not nullable.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
137
object deserializedValue;
139
if (converter != null && converter.CanRead)
140
deserializedValue = DeserializeConvertable(converter, reader, objectType, null);
142
deserializedValue = CreateValueInternal(reader, objectType, contract, null, null, null, null);
144
if (checkAdditionalContent)
146
if (reader.Read() && reader.TokenType != JsonToken.Comment)
147
throw new JsonSerializationException("Additional text found in JSON string after finishing deserializing object.");
150
return deserializedValue;
154
if (IsErrorHandled(null, contract, null, reader as IJsonLineInfo, reader.Path, ex))
156
HandleError(reader, false, 0);
166
private JsonSerializerProxy GetInternalSerializer()
168
if (_internalSerializer == null)
169
_internalSerializer = new JsonSerializerProxy(this);
171
return _internalSerializer;
174
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
175
private JsonFormatterConverter GetFormatterConverter()
177
if (_formatterConverter == null)
178
_formatterConverter = new JsonFormatterConverter(GetInternalSerializer());
180
return _formatterConverter;
184
private JToken CreateJToken(JsonReader reader, JsonContract contract)
186
ValidationUtils.ArgumentNotNull(reader, "reader");
188
if (contract != null && contract.UnderlyingType == typeof (JRaw))
190
return JRaw.Create(reader);
195
using (JTokenWriter writer = new JTokenWriter())
197
writer.WriteToken(reader);
198
token = writer.Token;
205
private JToken CreateJObject(JsonReader reader)
207
ValidationUtils.ArgumentNotNull(reader, "reader");
209
// this is needed because we've already read inside the object, looking for special properties
211
using (JTokenWriter writer = new JTokenWriter())
213
writer.WriteStartObject();
215
if (reader.TokenType == JsonToken.PropertyName)
216
writer.WriteToken(reader, reader.Depth - 1);
218
writer.WriteEndObject();
220
token = writer.Token;
226
private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
228
if (contract != null && contract.ContractType == JsonContractType.Linq)
229
return CreateJToken(reader, contract);
233
switch (reader.TokenType)
235
// populate a typed object or generic dictionary/array
236
// depending upon whether an objectType was supplied
237
case JsonToken.StartObject:
238
return CreateObject(reader, objectType, contract, member, containerContract, containerMember, existingValue);
239
case JsonToken.StartArray:
240
return CreateList(reader, objectType, contract, member, existingValue, null);
241
case JsonToken.Integer:
242
case JsonToken.Float:
243
case JsonToken.Boolean:
245
case JsonToken.Bytes:
246
return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
247
case JsonToken.String:
248
// convert empty string to null automatically for nullable types
249
if (string.IsNullOrEmpty((string)reader.Value) && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable)
252
// string that needs to be returned as a byte array should be base 64 decoded
253
if (objectType == typeof (byte[]))
254
return Convert.FromBase64String((string) reader.Value);
256
return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
257
case JsonToken.StartConstructor:
258
string constructorName = reader.Value.ToString();
260
return EnsureType(reader, constructorName, CultureInfo.InvariantCulture, contract, objectType);
262
case JsonToken.Undefined:
263
#if !(NETFX_CORE || PORTABLE)
264
if (objectType == typeof (DBNull))
268
return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
270
return new JRaw((string) reader.Value);
271
case JsonToken.Comment:
275
throw JsonSerializationException.Create(reader, "Unexpected token while deserializing object: " + reader.TokenType);
277
} while (reader.Read());
279
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
282
internal string GetExpectedDescription(JsonContract contract)
284
switch (contract.ContractType)
286
case JsonContractType.Object:
287
case JsonContractType.Dictionary:
288
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
289
case JsonContractType.Serializable:
291
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
292
case JsonContractType.Dynamic:
294
return @"JSON object (e.g. {""name"":""value""})";
295
case JsonContractType.Array:
296
return @"JSON array (e.g. [1,2,3])";
297
case JsonContractType.Primitive:
298
return @"JSON primitive value (e.g. string, number, boolean, null)";
299
case JsonContractType.String:
300
return @"JSON string value";
302
throw new ArgumentOutOfRangeException();
306
private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract, JsonProperty containerProperty)
308
JsonConverter converter = null;
309
if (memberConverter != null)
311
// member attribute converter
312
converter = memberConverter;
314
else if (containerProperty != null && containerProperty.ItemConverter != null)
316
converter = containerProperty.ItemConverter;
318
else if (containerContract != null && containerContract.ItemConverter != null)
320
converter = containerContract.ItemConverter;
322
else if (contract != null)
324
JsonConverter matchingConverter;
325
if (contract.Converter != null)
326
// class attribute converter
327
converter = contract.Converter;
328
else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
329
// passed in converters
330
converter = matchingConverter;
331
else if (contract.InternalConverter != null)
332
// internally specified converter
333
converter = contract.InternalConverter;
338
private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
344
if (ReadSpecialProperties(reader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
347
if (!HasDefinedType(objectType))
348
return CreateJObject(reader);
350
if (contract == null)
351
throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
353
switch (contract.ContractType)
355
case JsonContractType.Object:
356
bool createdFromNonDefaultConstructor = false;
357
JsonObjectContract objectContract = (JsonObjectContract) contract;
359
if (existingValue != null)
360
targetObject = existingValue;
362
targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultConstructor);
364
// don't populate if read from non-default constructor because the object has already been read
365
if (createdFromNonDefaultConstructor)
368
return PopulateObject(targetObject, reader, objectContract, member, id);
369
case JsonContractType.Primitive:
370
JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract) contract;
371
// if the content is inside $value then read past it
372
if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal))
375
object value = CreateValueInternal(reader, objectType, primitiveContract, member, null, null, existingValue);
381
case JsonContractType.Dictionary:
382
JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) contract;
383
object targetDictionary;
384
if (existingValue != null)
385
targetDictionary = existingValue;
387
targetDictionary = CreateNewDictionary(reader, dictionaryContract);
389
return PopulateDictionary(dictionaryContract.CreateWrapper(targetDictionary), reader, dictionaryContract, member, id);
390
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
391
case JsonContractType.Dynamic:
392
JsonDynamicContract dynamicContract = (JsonDynamicContract) contract;
393
return CreateDynamic(reader, dynamicContract, member, id);
395
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
396
case JsonContractType.Serializable:
397
JsonISerializableContract serializableContract = (JsonISerializableContract) contract;
398
return CreateISerializable(reader, serializableContract, id);
402
throw JsonSerializationException.Create(reader, @"Cannot deserialize the current JSON object (e.g. {{""name"":""value""}}) into type '{0}' because the type requires a {1} to deserialize correctly.
403
To fix this error either change the JSON to a {1} or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
404
".FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract)));
407
private bool ReadSpecialProperties(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
412
if (reader.TokenType == JsonToken.PropertyName)
414
string propertyName = reader.Value.ToString();
416
if (propertyName.Length > 0 && propertyName[0] == '$')
418
// read 'special' properties
419
// $type, $id, $ref, etc
420
bool specialProperty;
424
propertyName = reader.Value.ToString();
426
if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
429
if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null)
430
throw JsonSerializationException.Create(reader, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
432
string reference = (reader.Value != null) ? reader.Value.ToString() : null;
436
if (reference != null)
438
if (reader.TokenType == JsonToken.PropertyName)
439
throw JsonSerializationException.Create(reader, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
441
newValue = Serializer.ReferenceResolver.ResolveReference(this, reference);
443
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
444
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null);
450
specialProperty = true;
453
else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
456
string qualifiedTypeName = reader.Value.ToString();
458
TypeNameHandling resolvedTypeNameHandling =
459
((member != null) ? member.TypeNameHandling : null)
460
?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
461
?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null)
462
?? Serializer.TypeNameHandling;
464
if (resolvedTypeNameHandling != TypeNameHandling.None)
468
ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);
473
specifiedType = Serializer.Binder.BindToType(assemblyName, typeName);
477
throw JsonSerializationException.Create(reader, "Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
480
if (specifiedType == null)
481
throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
483
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
484
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved type '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName, specifiedType)), null);
486
if (objectType != null
487
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
488
&& objectType != typeof (IDynamicMetaObjectProvider)
490
&& !objectType.IsAssignableFrom(specifiedType))
491
throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
493
objectType = specifiedType;
494
contract = GetContractSafe(specifiedType);
499
specialProperty = true;
501
else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
505
id = (reader.Value != null) ? reader.Value.ToString() : null;
508
specialProperty = true;
510
else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
513
object list = CreateList(reader, objectType, contract, member, existingValue, id);
520
specialProperty = false;
522
} while (specialProperty
523
&& reader.TokenType == JsonToken.PropertyName);
529
private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)
531
if (contract == null)
532
throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
534
JsonArrayContract arrayContract = contract as JsonArrayContract;
535
if (arrayContract == null)
536
throw JsonSerializationException.Create(reader, @"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type '{0}' because the type requires a {1} to deserialize correctly.
537
To fix this error either change the JSON to a {1} or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
538
".FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract)));
540
return arrayContract;
543
private void CheckedRead(JsonReader reader)
546
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
549
private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id)
552
if (HasDefinedType(objectType))
554
JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract);
556
if (existingValue == null)
558
bool isTemporaryListReference;
559
IList list = CollectionUtils.CreateList(contract.CreatedType, out isTemporaryListReference);
561
if (id != null && isTemporaryListReference)
562
throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
565
if (contract.OnSerializing != null && isTemporaryListReference)
566
throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
568
if (contract.OnError != null && isTemporaryListReference)
569
throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
571
if (!arrayContract.IsMultidimensionalArray)
572
PopulateList(arrayContract.CreateWrapper(list), reader, arrayContract, member, id);
574
PopulateMultidimensionalArray(list, reader, arrayContract, member, id);
576
// create readonly and fixed sized collections using the temporary list
577
if (isTemporaryListReference)
579
if (arrayContract.IsMultidimensionalArray)
581
list = CollectionUtils.ToMultidimensionalArray(list, ReflectionUtils.GetCollectionItemType(contract.CreatedType), contract.CreatedType.GetArrayRank());
583
else if (contract.CreatedType.IsArray)
585
list = CollectionUtils.ToArray(((List<object>) list).ToArray(), ReflectionUtils.GetCollectionItemType(contract.CreatedType));
587
else if (ReflectionUtils.InheritsGenericDefinition(contract.CreatedType, typeof(ReadOnlyCollection<>)))
589
list = (IList) ReflectionUtils.CreateInstance(contract.CreatedType, list);
592
else if (list is IWrappedCollection)
594
return ((IWrappedCollection)list).UnderlyingCollection;
601
value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, arrayContract, member, id);
606
value = CreateJToken(reader, contract);
611
private bool HasDefinedType(Type type)
613
return (type != null && type != typeof (object) && !typeof (JToken).IsSubclassOf(type)
614
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
615
&& type != typeof (IDynamicMetaObjectProvider)
620
private object EnsureType(JsonReader reader, object value, CultureInfo culture, JsonContract contract, Type targetType)
622
if (targetType == null)
625
Type valueType = ReflectionUtils.GetObjectType(value);
627
// type of value and type of target don't match
628
// attempt to convert value's type to target's type
629
if (valueType != targetType)
633
if (value == null && contract.IsNullable)
636
if (contract.IsConvertable)
638
if (contract.NonNullableUnderlyingType.IsEnum())
641
return Enum.Parse(contract.NonNullableUnderlyingType, value.ToString(), true);
642
else if (ConvertUtils.IsInteger(value))
643
return Enum.ToObject(contract.NonNullableUnderlyingType, value);
646
return Convert.ChangeType(value, contract.NonNullableUnderlyingType, culture);
649
return ConvertUtils.ConvertOrCast(value, culture, contract.NonNullableUnderlyingType);
653
throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, FormatValueForPrint(value), targetType), ex);
660
private string FormatValueForPrint(object value)
666
return @"""" + value + @"""";
668
return value.ToString();
671
private void SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
674
bool useExistingValue;
675
JsonContract propertyContract;
676
bool gottenCurrentValue;
678
if (CalculatePropertyDetails(property, ref propertyConverter, containerContract, containerProperty, reader, target, out useExistingValue, out currentValue, out propertyContract, out gottenCurrentValue))
683
if (propertyConverter != null && propertyConverter.CanRead)
685
if (!gottenCurrentValue && target != null && property.Readable)
686
currentValue = property.ValueProvider.GetValue(target);
688
value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, currentValue);
692
value = CreateValueInternal(reader, property.PropertyType, propertyContract, property, containerContract, containerProperty, (useExistingValue) ? currentValue : null);
695
// always set the value if useExistingValue is false,
696
// otherwise also set it if CreateValue returns a new value compared to the currentValue
697
// this could happen because of a JsonConverter against the type
698
if ((!useExistingValue || value != currentValue)
699
&& ShouldSetPropertyValue(property, value))
701
property.ValueProvider.SetValue(target, value);
703
if (property.SetIsSpecified != null)
705
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
706
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "IsSpecified for property '{0}' on {1} set to true.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName, property.DeclaringType)), null);
708
property.SetIsSpecified(target, true);
713
private bool CalculatePropertyDetails(JsonProperty property, ref JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target, out bool useExistingValue, out object currentValue, out JsonContract propertyContract, out bool gottenCurrentValue)
716
useExistingValue = false;
717
propertyContract = null;
718
gottenCurrentValue = false;
720
if (property.Ignored)
726
ObjectCreationHandling objectCreationHandling =
727
property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
729
if ((objectCreationHandling == ObjectCreationHandling.Auto || objectCreationHandling == ObjectCreationHandling.Reuse)
730
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
731
&& property.Readable)
733
currentValue = property.ValueProvider.GetValue(target);
734
gottenCurrentValue = true;
736
useExistingValue = (currentValue != null
737
&& !property.PropertyType.IsArray
738
&& !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof (ReadOnlyCollection<>))
739
&& !property.PropertyType.IsValueType());
742
if (!property.Writable && !useExistingValue)
748
// test tokentype here because null might not be convertable to some types, e.g. ignoring null when applied to DateTime
749
if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && reader.TokenType == JsonToken.Null)
755
// test tokentype here because default value might not be convertable to actual type, e.g. default of "" for DateTime
756
if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore)
757
&& JsonReader.IsPrimitiveToken(reader.TokenType)
758
&& MiscellaneousUtils.ValueEquals(reader.Value, property.GetResolvedDefaultValue()))
764
if (property.PropertyContract == null)
765
property.PropertyContract = GetContractSafe(property.PropertyType);
767
if (currentValue == null)
769
propertyContract = property.PropertyContract;
773
propertyContract = GetContractSafe(currentValue.GetType());
775
if (propertyContract != property.PropertyContract)
776
propertyConverter = GetConverter(propertyContract, property.MemberConverter, containerContract, containerProperty);
782
private void AddReference(JsonReader reader, string id, object value)
786
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
787
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Read object reference Id '{0}' for {1}.".FormatWith(CultureInfo.InvariantCulture, id, value.GetType())), null);
789
Serializer.ReferenceResolver.AddReference(this, id, value);
793
throw JsonSerializationException.Create(reader, "Error reading object reference '{0}'.".FormatWith(CultureInfo.InvariantCulture, id), ex);
797
private bool HasFlag(DefaultValueHandling value, DefaultValueHandling flag)
799
return ((value & flag) == flag);
802
private bool ShouldSetPropertyValue(JsonProperty property, object value)
804
if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && value == null)
807
if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore)
808
&& MiscellaneousUtils.ValueEquals(value, property.GetResolvedDefaultValue()))
811
if (!property.Writable)
817
public object CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract)
821
if (contract.DefaultCreator != null &&
822
(!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
823
dictionary = contract.DefaultCreator();
825
throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
830
private void OnDeserializing(JsonReader reader, JsonContract contract, object value)
832
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
833
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);
835
contract.InvokeOnDeserializing(value, Serializer.Context);
838
private void OnDeserialized(JsonReader reader, JsonContract contract, object value)
840
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
841
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Finished deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);
843
contract.InvokeOnDeserialized(value, Serializer.Context);
846
private object PopulateDictionary(IWrappedDictionary wrappedDictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id)
848
object dictionary = wrappedDictionary.UnderlyingDictionary;
851
AddReference(reader, id, dictionary);
853
OnDeserializing(reader, contract, dictionary);
855
int initialDepth = reader.Depth;
857
if (contract.KeyContract == null)
858
contract.KeyContract = GetContractSafe(contract.DictionaryKeyType);
860
if (contract.ItemContract == null)
861
contract.ItemContract = GetContractSafe(contract.DictionaryValueType);
863
JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty);
865
bool finished = false;
868
switch (reader.TokenType)
870
case JsonToken.PropertyName:
871
object keyValue = reader.Value;
876
keyValue = EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType);
880
throw JsonSerializationException.Create(reader, "Could not convert string '{0}' to dictionary key type '{1}'. Create a TypeConverter to convert from the string to the key type object.".FormatWith(CultureInfo.InvariantCulture, reader.Value, contract.DictionaryKeyType), ex);
883
if (!ReadForType(reader, contract.ItemContract, dictionaryValueConverter != null))
884
throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
887
if (dictionaryValueConverter != null && dictionaryValueConverter.CanRead)
888
itemValue = DeserializeConvertable(dictionaryValueConverter, reader, contract.DictionaryValueType, null);
890
itemValue = CreateValueInternal(reader, contract.DictionaryValueType, contract.ItemContract, null, contract, containerProperty, null);
892
wrappedDictionary[keyValue] = itemValue;
896
if (IsErrorHandled(dictionary, contract, keyValue, reader as IJsonLineInfo, reader.Path, ex))
897
HandleError(reader, true, initialDepth);
902
case JsonToken.Comment:
904
case JsonToken.EndObject:
908
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
910
} while (!finished && reader.Read());
913
ThrowUnexpectedEndException(reader, contract, dictionary, "Unexpected end when deserializing object.");
915
OnDeserialized(reader, contract, dictionary);
919
private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
921
int rank = contract.UnderlyingType.GetArrayRank();
924
AddReference(reader, id, list);
926
OnDeserializing(reader, contract, list);
928
JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
929
JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);
931
int? previousErrorIndex = null;
932
Stack<IList> listStack = new Stack<IList>();
933
listStack.Push(list);
934
IList currentList = list;
936
bool finished = false;
939
int initialDepth = reader.Depth;
941
if (listStack.Count == rank)
945
if (ReadForType(reader, collectionItemContract, collectionItemConverter != null))
947
switch (reader.TokenType)
949
case JsonToken.EndArray:
951
currentList = listStack.Peek();
952
previousErrorIndex = null;
954
case JsonToken.Comment:
959
if (collectionItemConverter != null && collectionItemConverter.CanRead)
960
value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
962
value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
964
currentList.Add(value);
975
JsonPosition errorPosition = reader.GetPosition(initialDepth);
977
if (IsErrorHandled(list, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
979
HandleError(reader, true, initialDepth);
981
if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
983
// reader index has not moved since previous error handling
984
// break out of reading array to prevent infinite loop
985
throw JsonSerializationException.Create(reader, "Infinite loop detected from error handling.", ex);
989
previousErrorIndex = errorPosition.Position;
1002
switch (reader.TokenType)
1004
case JsonToken.StartArray:
1005
IList newList = new List<object>();
1006
currentList.Add(newList);
1007
listStack.Push(newList);
1008
currentList = newList;
1010
case JsonToken.EndArray:
1013
if (listStack.Count > 0)
1015
currentList = listStack.Peek();
1022
case JsonToken.Comment:
1025
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing multidimensional array: " + reader.TokenType);
1033
} while (!finished);
1036
ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
1038
OnDeserialized(reader, contract, list);
1042
private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object currentObject, string message)
1046
throw JsonSerializationException.Create(reader, message);
1048
catch (Exception ex)
1050
if (IsErrorHandled(currentObject, contract, null, reader as IJsonLineInfo, reader.Path, ex))
1051
HandleError(reader, false, 0);
1057
private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
1059
object list = wrappedList.UnderlyingCollection;
1062
AddReference(reader, id, list);
1064
// can't populate an existing array
1065
if (wrappedList.IsFixedSize)
1071
OnDeserializing(reader, contract, list);
1073
int initialDepth = reader.Depth;
1075
JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
1076
JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);
1078
int? previousErrorIndex = null;
1080
bool finished = false;
1085
if (ReadForType(reader, collectionItemContract, collectionItemConverter != null))
1087
switch (reader.TokenType)
1089
case JsonToken.EndArray:
1092
case JsonToken.Comment:
1097
if (collectionItemConverter != null && collectionItemConverter.CanRead)
1098
value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
1100
value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
1102
wrappedList.Add(value);
1111
catch (Exception ex)
1113
JsonPosition errorPosition = reader.GetPosition(initialDepth);
1115
if (IsErrorHandled(list, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
1117
HandleError(reader, true, initialDepth);
1119
if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
1121
// reader index has not moved since previous error handling
1122
// break out of reading array to prevent infinite loop
1123
throw JsonSerializationException.Create(reader, "Infinite loop detected from error handling.", ex);
1127
previousErrorIndex = errorPosition.Position;
1135
} while (!finished);
1138
ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
1140
OnDeserialized(reader, contract, list);
1144
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
1145
private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, string id)
1147
Type objectType = contract.UnderlyingType;
1149
if (!JsonTypeReflector.FullyTrusted)
1151
throw JsonSerializationException.Create(reader, @"Type '{0}' implements ISerializable but cannot be deserialized using the ISerializable interface because the current application is not fully trusted and ISerializable can expose secure data.
1152
To fix this error either change the environment to be fully trusted, change the application to not deserialize the type, add JsonObjectAttribute to the type or change the JsonSerializer setting ContractResolver to use a new DefaultContractResolver with IgnoreSerializableInterface set to true.
1153
".FormatWith(CultureInfo.InvariantCulture, objectType));
1156
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
1157
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using ISerializable constructor.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);
1159
SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, GetFormatterConverter());
1161
bool finished = false;
1164
switch (reader.TokenType)
1166
case JsonToken.PropertyName:
1167
string memberName = reader.Value.ToString();
1169
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
1171
serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
1173
case JsonToken.Comment:
1175
case JsonToken.EndObject:
1179
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
1181
} while (!finished && reader.Read());
1184
ThrowUnexpectedEndException(reader, contract, serializationInfo, "Unexpected end when deserializing object.");
1186
if (contract.ISerializableCreator == null)
1187
throw JsonSerializationException.Create(reader, "ISerializable type '{0}' does not have a valid constructor. To correctly implement ISerializable a constructor that takes SerializationInfo and StreamingContext parameters should be present.".FormatWith(CultureInfo.InvariantCulture, objectType));
1189
object createdObject = contract.ISerializableCreator(serializationInfo, Serializer.Context);
1192
AddReference(reader, id, createdObject);
1194
// these are together because OnDeserializing takes an object but for an ISerializable the object is fully created in the constructor
1195
OnDeserializing(reader, contract, createdObject);
1196
OnDeserialized(reader, contract, createdObject);
1198
return createdObject;
1202
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
1203
private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, JsonProperty member, string id)
1205
IDynamicMetaObjectProvider newObject;
1207
if (contract.UnderlyingType.IsInterface() || contract.UnderlyingType.IsAbstract())
1208
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
1210
if (contract.DefaultCreator != null &&
1211
(!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
1212
newObject = (IDynamicMetaObjectProvider) contract.DefaultCreator();
1214
throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
1217
AddReference(reader, id, newObject);
1219
OnDeserializing(reader, contract, newObject);
1221
int initialDepth = reader.Depth;
1223
bool finished = false;
1226
switch (reader.TokenType)
1228
case JsonToken.PropertyName:
1229
string memberName = reader.Value.ToString();
1234
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
1236
// first attempt to find a settable property, otherwise fall back to a dynamic set without type
1237
JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
1239
if (property != null && property.Writable && !property.Ignored)
1241
if (property.PropertyContract == null)
1242
property.PropertyContract = GetContractSafe(property.PropertyType);
1244
JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, null, null);
1246
SetPropertyValue(property, propertyConverter, null, member, reader, newObject);
1250
Type t = (JsonReader.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType : typeof (IDynamicMetaObjectProvider);
1252
JsonContract dynamicMemberContract = GetContractSafe(t);
1253
JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member);
1256
if (dynamicMemberConverter != null && dynamicMemberConverter.CanRead)
1257
value = DeserializeConvertable(dynamicMemberConverter, reader, t, null);
1259
value = CreateValueInternal(reader, t, dynamicMemberContract, null, null, member, null);
1261
newObject.TrySetMember(memberName, value);
1264
catch (Exception ex)
1266
if (IsErrorHandled(newObject, contract, memberName, reader as IJsonLineInfo, reader.Path, ex))
1267
HandleError(reader, true, initialDepth);
1272
case JsonToken.EndObject:
1276
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
1278
} while (!finished && reader.Read());
1281
ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
1283
OnDeserialized(reader, contract, newObject);
1289
private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ConstructorInfo constructorInfo, string id)
1291
ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo");
1293
Type objectType = contract.UnderlyingType;
1295
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
1296
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using a non-default constructor '{1}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, constructorInfo)), null);
1298
IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndConstructorValues(contract, containerProperty, reader, objectType);
1300
IDictionary<ParameterInfo, object> constructorParameters = constructorInfo.GetParameters().ToDictionary(p => p, p => (object) null);
1301
IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
1303
foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
1305
ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.UnderlyingName).Key;
1306
if (matchingConstructorParameter != null)
1307
constructorParameters[matchingConstructorParameter] = propertyValue.Value;
1309
remainingPropertyValues.Add(propertyValue);
1312
object createdObject = constructorInfo.Invoke(constructorParameters.Values.ToArray());
1315
AddReference(reader, id, createdObject);
1317
OnDeserializing(reader, contract, createdObject);
1319
// go through unused values and set the newly created object's properties
1320
foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues)
1322
JsonProperty property = remainingPropertyValue.Key;
1323
object value = remainingPropertyValue.Value;
1325
if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value))
1327
property.ValueProvider.SetValue(createdObject, value);
1329
else if (!property.Writable && value != null)
1331
// handle readonly collection/dictionary properties
1332
JsonContract propertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType);
1334
if (propertyContract.ContractType == JsonContractType.Array)
1336
JsonArrayContract propertyArrayContract = (JsonArrayContract)propertyContract;
1338
object createdObjectCollection = property.ValueProvider.GetValue(createdObject);
1339
if (createdObjectCollection != null)
1341
IWrappedCollection createdObjectCollectionWrapper = propertyArrayContract.CreateWrapper(createdObjectCollection);
1342
IWrappedCollection newValues = propertyArrayContract.CreateWrapper(value);
1344
foreach (object newValue in newValues)
1346
createdObjectCollectionWrapper.Add(newValue);
1350
else if (propertyContract.ContractType == JsonContractType.Dictionary)
1352
JsonDictionaryContract jsonDictionaryContract = (JsonDictionaryContract)propertyContract;
1354
object createdObjectDictionary = property.ValueProvider.GetValue(createdObject);
1355
if (createdObjectDictionary != null)
1357
IWrappedDictionary createdObjectDictionaryWrapper = jsonDictionaryContract.CreateWrapper(createdObjectDictionary);
1358
IWrappedDictionary newValues = jsonDictionaryContract.CreateWrapper(value);
1360
foreach (DictionaryEntry newValue in newValues)
1362
createdObjectDictionaryWrapper.Add(newValue.Key, newValue.Value);
1369
OnDeserialized(reader, contract, createdObject);
1370
return createdObject;
1373
private object DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object existingValue)
1375
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
1376
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, objectType, converter.GetType())), null);
1378
object value = converter.ReadJson(reader, objectType, existingValue, GetInternalSerializer());
1380
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
1381
TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Finished deserializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, objectType, converter.GetType())), null);
1386
private IDictionary<JsonProperty, object> ResolvePropertyAndConstructorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
1388
IDictionary<JsonProperty, object> propertyValues = new Dictionary<JsonProperty, object>();
1392
switch (reader.TokenType)
1394
case JsonToken.PropertyName:
1395
string memberName = reader.Value.ToString();
1397
// attempt exact case match first
1398
// then try match ignoring case
1399
JsonProperty property = contract.ConstructorParameters.GetClosestMatchProperty(memberName) ??
1400
contract.Properties.GetClosestMatchProperty(memberName);
1402
if (property != null)
1404
if (property.PropertyContract == null)
1405
property.PropertyContract = GetContractSafe(property.PropertyType);
1407
JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, containerProperty);
1409
if (!ReadForType(reader, property.PropertyContract, propertyConverter != null))
1410
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
1412
if (!property.Ignored)
1414
if (property.PropertyContract == null)
1415
property.PropertyContract = GetContractSafe(property.PropertyType);
1417
object propertyValue;
1418
if (propertyConverter != null && propertyConverter.CanRead)
1419
propertyValue = DeserializeConvertable(propertyConverter, reader, property.PropertyType, null);
1421
propertyValue = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null);
1423
propertyValues[property] = propertyValue;
1433
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
1435
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
1436
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}.".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null);
1438
if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
1439
throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
1444
case JsonToken.Comment:
1446
case JsonToken.EndObject:
1450
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
1452
} while (!exit && reader.Read());
1454
return propertyValues;
1457
private bool ReadForType(JsonReader reader, JsonContract contract, bool hasConverter)
1459
// don't read properties with converters as a specific value
1460
// the value might be a string which will then get converted which will error if read as date for example
1462
return reader.Read();
1464
ReadType t = (contract != null) ? contract.InternalReadType : ReadType.Read;
1473
} while (reader.TokenType == JsonToken.Comment);
1476
case ReadType.ReadAsInt32:
1477
reader.ReadAsInt32();
1479
case ReadType.ReadAsDecimal:
1480
reader.ReadAsDecimal();
1482
case ReadType.ReadAsBytes:
1483
reader.ReadAsBytes();
1485
case ReadType.ReadAsString:
1486
reader.ReadAsString();
1488
case ReadType.ReadAsDateTime:
1489
reader.ReadAsDateTime();
1492
case ReadType.ReadAsDateTimeOffset:
1493
reader.ReadAsDateTimeOffset();
1497
throw new ArgumentOutOfRangeException();
1500
return (reader.TokenType != JsonToken.None);
1503
public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultConstructor)
1505
object newObject = null;
1507
if (objectContract.UnderlyingType.IsInterface() || objectContract.UnderlyingType.IsAbstract())
1508
throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
1510
if (objectContract.OverrideConstructor != null)
1512
if (objectContract.OverrideConstructor.GetParameters().Length > 0)
1514
createdFromNonDefaultConstructor = true;
1515
return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.OverrideConstructor, id);
1518
newObject = objectContract.OverrideConstructor.Invoke(null);
1520
else if (objectContract.DefaultCreator != null &&
1521
(!objectContract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedConstructor == null))
1523
// use the default constructor if it is...
1525
// non-public and the user has change constructor handling settings
1526
// non-public and there is no other constructor
1527
newObject = objectContract.DefaultCreator();
1529
else if (objectContract.ParametrizedConstructor != null)
1531
createdFromNonDefaultConstructor = true;
1532
return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedConstructor, id);
1535
if (newObject == null)
1536
throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
1538
createdFromNonDefaultConstructor = false;
1542
private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
1544
OnDeserializing(reader, contract, newObject);
1546
// only need to keep a track of properies presence if they are required or a value should be defaulted if missing
1547
Dictionary<JsonProperty, PropertyPresence> propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer.DefaultValueHandling, DefaultValueHandling.Populate))
1548
? contract.Properties.ToDictionary(m => m, m => PropertyPresence.None)
1552
AddReference(reader, id, newObject);
1554
int initialDepth = reader.Depth;
1556
bool finished = false;
1559
switch (reader.TokenType)
1561
case JsonToken.PropertyName:
1563
string memberName = reader.Value.ToString();
1567
// attempt exact case match first
1568
// then try match ignoring case
1569
JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
1571
if (property == null)
1573
if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
1574
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null);
1576
if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
1577
throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
1583
if (property.PropertyContract == null)
1584
property.PropertyContract = GetContractSafe(property.PropertyType);
1586
JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, member);
1588
if (!ReadForType(reader, property.PropertyContract, propertyConverter != null))
1589
throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
1591
SetPropertyPresence(reader, property, propertiesPresence);
1593
SetPropertyValue(property, propertyConverter, contract, member, reader, newObject);
1595
catch (Exception ex)
1597
if (IsErrorHandled(newObject, contract, memberName, reader as IJsonLineInfo, reader.Path, ex))
1598
HandleError(reader, true, initialDepth);
1604
case JsonToken.EndObject:
1607
case JsonToken.Comment:
1611
throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
1613
} while (!finished && reader.Read());
1616
ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
1618
EndObject(newObject, reader, contract, initialDepth, propertiesPresence);
1620
OnDeserialized(reader, contract, newObject);
1624
private void EndObject(object newObject, JsonReader reader, JsonObjectContract contract, int initialDepth, Dictionary<JsonProperty, PropertyPresence> propertiesPresence)
1626
if (propertiesPresence != null)
1628
foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence)
1630
JsonProperty property = propertyPresence.Key;
1631
PropertyPresence presence = propertyPresence.Value;
1633
if (presence == PropertyPresence.None || presence == PropertyPresence.Null)
1637
Required resolvedRequired = property._required ?? contract.ItemRequired ?? Required.Default;
1641
case PropertyPresence.None:
1642
if (resolvedRequired == Required.AllowNull || resolvedRequired == Required.Always)
1643
throw JsonSerializationException.Create(reader, "Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
1645
if (property.PropertyContract == null)
1646
property.PropertyContract = GetContractSafe(property.PropertyType);
1648
if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Populate) && property.Writable)
1649
property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType));
1651
case PropertyPresence.Null:
1652
if (resolvedRequired == Required.Always)
1653
throw JsonSerializationException.Create(reader, "Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
1657
catch (Exception ex)
1659
if (IsErrorHandled(newObject, contract, property.PropertyName, reader as IJsonLineInfo, reader.Path, ex))
1660
HandleError(reader, true, initialDepth);
1669
private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dictionary<JsonProperty, PropertyPresence> requiredProperties)
1671
if (property != null && requiredProperties != null)
1673
requiredProperties[property] = (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.Undefined)
1674
? PropertyPresence.Null
1675
: PropertyPresence.Value;
1679
private void HandleError(JsonReader reader, bool readPastError, int initialDepth)
1681
ClearErrorContext();
1687
while (reader.Depth > (initialDepth + 1))
b'\\ No newline at end of file'