Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs

Symbol Coverage: 92.62% (389 of 420)

Branch Coverage: 93.10% (270 of 290)

Cyclomatic Complexity Avg: 5.00 Max:23

Code Lines: 424


L V Source
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

  
26
using System;
27
using System.Collections;
28
using System.Collections.Generic;
29
using System.Collections.ObjectModel;
30
using System.Globalization;
31
using System.Linq;
32
using System.Reflection;
33
using System.Runtime.Serialization;
34
using Newtonsoft.Json.Linq;
35
using Newtonsoft.Json.Utilities;
36

  
37
namespace Newtonsoft.Json.Serialization
38
{
39
  internal class JsonSerializerInternalReader : JsonSerializerInternalBase
40
  {
41
    private JsonSerializerProxy _internalSerializer;
42
#if !SILVERLIGHT && !PocketPC
43
   private JsonFormatterConverter _formatterConverter;
44
#endif
45

  
46
 10234
    public JsonSerializerInternalReader(JsonSerializer serializer) : base(serializer)
47
    {
48
 10234
    }
49

  
50
    public void Populate(JsonReader reader, object target)
51
    {
52
 15
      ValidationUtils.ArgumentNotNull(target, "target");
53

  
54
 15
      Type objectType = target.GetType();
55

  
56
 15
      JsonContract contract = Serializer.ContractResolver.ResolveContract(objectType);
57

  
58
 15
      if (reader.TokenType == JsonToken.None)
59
 12
        reader.Read();
60

  
61
 15
      if (reader.TokenType == JsonToken.StartArray)
62
      {
63
 2
        if (contract is JsonArrayContract)
64
 1
          PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, null, (JsonArrayContract)contract);
65
        else
66
 1
          throw new JsonSerializationException("Cannot populate JSON array onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
67
      }
68
 13
      else if (reader.TokenType == JsonToken.StartObject)
69
      {
70
 12
        CheckedRead(reader);
71

  
72
 12
        string id = null;
73
 12
        if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
74
        {
75
 3
          CheckedRead(reader);
76
 3
          id = reader.Value.ToString();
77
 3
          CheckedRead(reader);
78
        }
79

  
80
 12
        if (contract is JsonDictionaryContract)
81
 1
          PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(target), reader, (JsonDictionaryContract) contract, id);
82
 11
        else if (contract is JsonObjectContract)
83
 10
          PopulateObject(target, reader, (JsonObjectContract) contract, id);
84
        else
85
 1
          throw new JsonSerializationException("Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
86
      }
87
      else
88
      {
89
 1
        throw new JsonSerializationException("Unexpected initial token '{0}' when populating object. Expected JSON object or array.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
90
      }
91
 12
    }
92

  
93
    private JsonContract GetContractSafe(Type type)
94
    {
95
 251170
      if (type == null)
96
 20
        return null;
97

  
98
 251150
      return Serializer.ContractResolver.ResolveContract(type);
99
 251170
    }
100

  
101
    private JsonContract GetContractSafe(Type type, object value)
102
    {
103
 160636
      if (value == null)
104
 160620
        return GetContractSafe(type);
105

  
106
 16
      return Serializer.ContractResolver.ResolveContract(value.GetType());
107
 160636
    }
108

  
109
    public object Deserialize(JsonReader reader, Type objectType)
110
    {
111
 10245
      if (reader == null)
112
 0
        throw new ArgumentNullException("reader");
113

  
114
 10245
      if (reader.TokenType == JsonToken.None && !reader.Read())
115
 0
        return null;
116

  
117
 10245
      return CreateValueNonProperty(reader, objectType, GetContractSafe(objectType));
118
 10216
    }
119

  
120
    private JsonSerializerProxy GetInternalSerializer()
121
    {
122
 113
      if (_internalSerializer == null)
123
 64
        _internalSerializer = new JsonSerializerProxy(this);
124

  
125
 113
      return _internalSerializer;
126
 113
    }
127

  
128
#if !SILVERLIGHT && !PocketPC
129
    private JsonFormatterConverter GetFormatterConverter()
130
    {
131
 1
      if (_formatterConverter == null)
132
 1
        _formatterConverter = new JsonFormatterConverter(GetInternalSerializer());
133

  
134
 1
      return _formatterConverter;
135
 1
    }
136
#endif
137

  
138
    private JToken CreateJToken(JsonReader reader, JsonContract contract)
139
    {
140
 10
      ValidationUtils.ArgumentNotNull(reader, "reader");
141

  
142
 10
      if (contract != null && contract.UnderlyingType == typeof(JRaw))
143
      {
144
 4
        return JRaw.Create(reader);
145
      }
146
      else
147
      {
148
        JToken token;
149
 6
        using (JTokenWriter writer = new JTokenWriter())
150
        {
151
 6
          writer.WriteToken(reader);
152
 6
          token = writer.Token;
153
        }
154

  
155
 6
        return token;
156
      }
157
 10
    }
158

  
159
    private JToken CreateJObject(JsonReader reader)
160
    {
161
 9
      ValidationUtils.ArgumentNotNull(reader, "reader");
162

  
163
      // this is needed because we've already read inside the object, looking for special properties
164
      JToken token;
165
 9
      using (JTokenWriter writer = new JTokenWriter())
166
      {
167
 9
        writer.WriteStartObject();
168

  
169
 9
        if (reader.TokenType == JsonToken.PropertyName)
170
 8
          writer.WriteToken(reader, reader.Depth - 1);
171
        else
172
 1
          writer.WriteEndObject();
173

  
174
 9
        token = writer.Token;
175
      }
176

  
177
 9
      return token;
178
 9
    }
179

  
180
    private object CreateValueProperty(JsonReader reader, JsonProperty property, object target, bool gottenCurrentValue, object currentValue)
181
    {
182
 160636
      JsonContract contract = GetContractSafe(property.PropertyType, currentValue);
183
 160636
      Type objectType = property.PropertyType;
184

  
185
 160636
      JsonConverter converter = GetConverter(contract, property.MemberConverter);
186

  
187
 160636
      if (converter != null && converter.CanRead)
188
      {
189
 55
        if (!gottenCurrentValue && target != null && property.Readable)
190
 40
          currentValue = property.ValueProvider.GetValue(target);
191

  
192
 55
        return converter.ReadJson(reader, objectType, currentValue, GetInternalSerializer());
193
      }
194

  
195
 160581
      return CreateValueInternal(reader, objectType, contract, property, currentValue);
196
 160631
    }
197

  
198
    private object CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract)
199
    {
200
 90539
      JsonConverter converter = GetConverter(contract, null);
201

  
202
 90539
      if (converter != null && converter.CanRead)
203
 57
        return converter.ReadJson(reader, objectType, null, GetInternalSerializer());
204

  
205
 90482
      return CreateValueInternal(reader, objectType, contract, null, null);
206
 90496
    }
207

  
208
    private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue)
209
    {
210
 251063
      if (contract is JsonLinqContract)
211
 4
        return CreateJToken(reader, contract);
212

  
213
      do
214
      {
215
 251062
        switch (reader.TokenType)
216
        {
217
            // populate a typed object or generic dictionary/array
218
            // depending upon whether an objectType was supplied
219
          case JsonToken.StartObject:
220
 50289
            return CreateObject(reader, objectType, contract, member, existingValue);
221
          case JsonToken.StartArray:
222
 20090
            return CreateList(reader, objectType, contract, member, existingValue, null);
223
          case JsonToken.Integer:
224
          case JsonToken.Float:
225
          case JsonToken.Boolean:
226
          case JsonToken.Date:
227
          case JsonToken.Bytes:
228
 80279
            return EnsureType(reader.Value, objectType);
229
          case JsonToken.String:
230
            // convert empty string to null automatically for nullable types
231
 80342
            if (string.IsNullOrEmpty((string)reader.Value) &&
232
 80342
              objectType != null &&
233
 80342
              ReflectionUtils.IsNullableType(objectType))
234
 1
              return null;
235

  
236
 80341
            return EnsureType(reader.Value, objectType);
237
          case JsonToken.StartConstructor:
238
          case JsonToken.EndConstructor:
239
 0
            string constructorName = reader.Value.ToString();
240

  
241
 0
            return constructorName;
242
          case JsonToken.Null:
243
          case JsonToken.Undefined:
244
 20059
            if (objectType == typeof (DBNull))
245
 1
              return DBNull.Value;
246

  
247
 20058
            return EnsureType(reader.Value, objectType);
248
          case JsonToken.Raw:
249
 0
            return new JRaw((string)reader.Value);
250
          case JsonToken.Comment:
251
            // ignore
252
 3
            break;
253
          default:
254
 0
            throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
255
        }
256
 3
      } while (reader.Read());
257

  
258
 0
      throw new JsonSerializationException("Unexpected end when deserializing object.");
259
 251030
    }
260

  
261
    private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter)
262
    {
263
 251175
      JsonConverter converter = null;
264
 251175
      if (memberConverter != null)
265
      {
266
        // member attribute converter
267
 6
        converter = memberConverter;
268
      }
269
 251169
      else if (contract != null)
270
      {
271
        JsonConverter matchingConverter;
272
 251149
        if (contract.Converter != null)
273
          // class attribute converter
274
 4
          converter = contract.Converter;
275
 251145
        else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
276
          // passed in converters
277
 83
          converter = matchingConverter;
278
 251062
        else if (contract.InternalConverter != null)
279
          // internally specified converter
280
 20
          converter = contract.InternalConverter;
281
      }
282
 251175
      return converter;
283
 251175
    }
284

  
285
    private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue)
286
    {
287
 50289
      CheckedRead(reader);
288

  
289
 50289
      string id = null;
290

  
291
 50289
      if (reader.TokenType == JsonToken.PropertyName)
292
      {
293
        bool specialProperty;
294

  
295
        do
296
        {
297
 50328
          string propertyName = reader.Value.ToString();
298

  
299
 50328
          if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
300
          {
301
 13
            CheckedRead(reader);
302
 13
            if (reader.TokenType != JsonToken.String)
303
 1
              throw new JsonSerializationException("JSON reference {0} property must have a string value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
304

  
305
 12
            string reference = reader.Value.ToString();
306

  
307
 12
            CheckedRead(reader);
308
 12
            if (reader.TokenType == JsonToken.PropertyName)
309
 1
              throw new JsonSerializationException("Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
310

  
311
 11
            return Serializer.ReferenceResolver.ResolveReference(reference);
312
          }
313
 50315
          else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
314
          {
315
 14
            CheckedRead(reader);
316
 14
            string qualifiedTypeName = reader.Value.ToString();
317

  
318
 14
            CheckedRead(reader);
319

  
320
 14
            if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) != TypeNameHandling.None)
321
            {
322
              string typeName;
323
              string assemblyName;
324
 13
              ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);
325

  
326
              Type specifiedType;
327
              try
328
              {
329
 13
                specifiedType = Serializer.Binder.BindToType(assemblyName, typeName);
330
              }
331
 0
              catch (Exception ex)
332
              {
333
 0
                throw new JsonSerializationException("Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
334
              }
335

  
336
 13
              if (specifiedType == null)
337
 1
                throw new JsonSerializationException("Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
338

  
339
 12
              if (objectType != null && !objectType.IsAssignableFrom(specifiedType))
340
 1
                throw new JsonSerializationException("Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
341

  
342
 11
              objectType = specifiedType;
343
 11
              contract = GetContractSafe(specifiedType);
344
            }
345
 12
            specialProperty = true;
346
          }
347
 50301
          else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
348
          {
349
 34
            CheckedRead(reader);
350

  
351
 33
            id = reader.Value.ToString();
352
 33
            CheckedRead(reader);
353
 33
            specialProperty = true;
354
          }
355
 50267
          else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
356
          {
357
 6
            CheckedRead(reader);
358
 6
            object list = CreateList(reader, objectType, contract, member, existingValue, id);
359
 5
            CheckedRead(reader);
360
 5
            return list;
361
          }
362
          else
363
          {
364
 50261
            specialProperty = false;
365
          }
366
 50306
        } while (specialProperty
367
 50306
                 && reader.TokenType == JsonToken.PropertyName);
368
      }
369

  
370
 50267
      if (!HasDefinedType(objectType))
371
 9
        return CreateJObject(reader);
372

  
373
 50258
      if (contract == null)
374
 0
        throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
375

  
376
 50258
      JsonDictionaryContract dictionaryContract = contract as JsonDictionaryContract;
377
 50258
      if (dictionaryContract != null)
378
      {
379
 10021
        if (existingValue == null)
380
 10019
          return CreateAndPopulateDictionary(reader, dictionaryContract, id);
381

  
382
 2
        return PopulateDictionary(dictionaryContract.CreateWrapper(existingValue), reader, dictionaryContract, id);
383
      }
384

  
385
 40237
      JsonObjectContract objectContract = contract as JsonObjectContract;
386
 40237
      if (objectContract != null)
387
      {
388
 40235
        if (existingValue == null)
389
 40233
          return CreateAndPopulateObject(reader, objectContract, id);
390

  
391
 2
        return PopulateObject(existingValue, reader, objectContract, id);
392
      }
393

  
394
#if !SILVERLIGHT && !PocketPC
395
 2
      JsonISerializableContract serializableContract = contract as JsonISerializableContract;
396
 2
      if (serializableContract != null)
397
      {
398
 1
        return CreateISerializable(reader, serializableContract, id);
399
      }
400
#endif
401
      
402
 1
      throw new JsonSerializationException("Cannot deserialize JSON object into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
403
 50263
    }
404

  
405
    private JsonArrayContract EnsureArrayContract(Type objectType, JsonContract contract)
406
    {
407
 20090
      if (contract == null)
408
 0
        throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
409

  
410
 20090
      JsonArrayContract arrayContract = contract as JsonArrayContract;
411
 20090
      if (arrayContract == null)
412
 1
        throw new JsonSerializationException("Cannot deserialize JSON array into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
413

  
414
 20089
      return arrayContract;
415
 20089
    }
416

  
417
    private void CheckedRead(JsonReader reader)
418
    {
419
 80483
      if (!reader.Read())
420
 1
        throw new JsonSerializationException("Unexpected end when deserializing object.");
421
 80482
    }
422

  
423
    private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string reference)
424
    {
425
      object value;
426
 20096
      if (HasDefinedType(objectType))
427
      {
428
 20090
        JsonArrayContract arrayContract = EnsureArrayContract(objectType, contract);
429

  
430
 20089
        if (existingValue == null)
431
 20079
          value = CreateAndPopulateList(reader, reference, arrayContract);
432
        else
433
 10
          value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, reference, arrayContract);
434
      }
435
      else
436
      {
437
 6
        value = CreateJToken(reader, contract);
438
      }
439
 20091
      return value;
440
 20091
    }
441

  
442
    private bool HasDefinedType(Type type)
443
    {
444
 70363
      return (type != null && type != typeof (object) && !type.IsSubclassOf(typeof(JToken)));
445
 70363
    }
446

  
447
    private object EnsureType(object value, Type targetType)
448
    {
449
 210724
      if (targetType == null)
450
 11
        return value;
451

  
452
 210713
      Type valueType = ReflectionUtils.GetObjectType(value);
453

  
454
      // type of value and type of target don't match
455
      // attempt to convert value's type to target's type
456
 210713
      if (valueType != targetType)
457
      {
458
        try
459
        {
460
 60306
          return ConvertUtils.ConvertOrCast(value, CultureInfo.InvariantCulture, targetType);
461
        }
462
 4
        catch (Exception ex)
463
        {
464
 4
          throw new JsonSerializationException("Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, FormatValueForPrint(value), targetType), ex);
465
        }
466
      }
467

  
468
 150407
      return value;
469
 210720
    }
470

  
471
    private string FormatValueForPrint(object value)
472
    {
473
 4
      if (value == null)
474
 1
        return "{null}";
475

  
476
 3
      if (value is string)
477
 3
        return @"""" + value + @"""";
478

  
479
 0
      return value.ToString();
480
 4
    }
481

  
482
    private void SetPropertyValue(JsonProperty property, JsonReader reader, object target)
483
    {
484
 160619
      if (property.Ignored)
485
      {
486
 4
        reader.Skip();
487
 4
        return;
488
      }
489

  
490
 160615
      object currentValue = null;
491
 160615
      bool useExistingValue = false;
492
 160615
      bool gottenCurrentValue = false;
493

  
494
 160615
      ObjectCreationHandling objectCreationHandling =
495
 160615
        property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
496

  
497
 160615
      if ((objectCreationHandling == ObjectCreationHandling.Auto || objectCreationHandling == ObjectCreationHandling.Reuse)
498
 160615
        && (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
499
 160615
        && property.Readable)
500
      {
501
 103
        currentValue = property.ValueProvider.GetValue(target);
502
 103
        gottenCurrentValue = true;
503

  
504
 103
        useExistingValue = (currentValue != null && !property.PropertyType.IsArray && !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof(ReadOnlyCollection<>)));
505
      }
506

  
507
 160615
      if (!property.Writable && !useExistingValue)
508
      {
509
 6
        reader.Skip();
510
 6
        return;
511
      }
512

  
513
 160609
      object existingValue = (useExistingValue) ? currentValue : null;
514
 160609
      object value = CreateValueProperty(reader, property, target, gottenCurrentValue, existingValue);
515

  
516
      // always set the value if useExistingValue is false,
517
      // otherwise also set it if CreateValue returns a new value compared to the currentValue
518
      // this could happen because of a JsonConverter against the type
519
 160604
      if ((!useExistingValue || value != currentValue)
520
 160604
        && ShouldSetPropertyValue(property, value))
521
 160589
        property.ValueProvider.SetValue(target, value);
522
 160611
    }
523

  
524
    private bool ShouldSetPropertyValue(JsonProperty property, object value)
525
    {
526
 160596
      if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && value == null)
527
 1
        return false;
528

  
529
 160595
      if (property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(value, property.DefaultValue))
530
 0
        return false;
531

  
532
 160595
      if (!property.Writable)
533
 0
        return false;
534

  
535
 160595
      return true;
536
 160596
    }
537

  
538
    private object CreateAndPopulateDictionary(JsonReader reader, JsonDictionaryContract contract, string id)
539
    {
540
      object dictionary;
541

  
542
 10019
      if (contract.DefaultCreator != null &&
543
 10019
        (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
544
 10018
        dictionary = contract.DefaultCreator();
545
      else
546
 1
        throw new JsonSerializationException("Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
547

  
548
 10018
      IWrappedDictionary dictionaryWrapper = contract.CreateWrapper(dictionary);
549

  
550
 10018
      PopulateDictionary(dictionaryWrapper, reader, contract, id);
551

  
552
 10015
      return dictionaryWrapper.UnderlyingDictionary;
553
 10015
    }
554

  
555
    private object PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, string id)
556
    {
557
 10021
      if (id != null)
558
 2
        Serializer.ReferenceResolver.AddReference(id, dictionary.UnderlyingDictionary);
559

  
560
 10021
      contract.InvokeOnDeserializing(dictionary.UnderlyingDictionary, Serializer.Context);
561

  
562
 10021
      int initialDepth = reader.Depth;
563

  
564
      do
565
      {
566
 40064
        switch (reader.TokenType)
567
        {
568
          case JsonToken.PropertyName:
569
            object keyValue;
570
            try
571
            {
572
 30046
              keyValue = EnsureType(reader.Value, contract.DictionaryKeyType);
573
            }
574
 1
            catch (Exception ex)
575
            {
576
 1
              throw new JsonSerializationException("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);
577
            }
578

  
579
 30045
            CheckedRead(reader);
580

  
581
            try
582
            {
583
 30045
              dictionary[keyValue] = CreateValueNonProperty(reader, contract.DictionaryValueType, GetContractSafe(contract.DictionaryValueType));
584
            }
585
 2
            catch (Exception ex)
586
            {
587
 2
              if (IsErrorHandled(dictionary, contract, keyValue, ex))
588
 0
                HandleError(reader, initialDepth);
589
              else
590
 2
                throw;
591
            }
592
 30043
            break;
593
          case JsonToken.EndObject:
594
 10018
            contract.InvokeOnDeserialized(dictionary.UnderlyingDictionary, Serializer.Context);
595
            
596
 10018
            return dictionary.UnderlyingDictionary;
597
          default:
598
 0
            throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
599
        }
600
 30043
      } while (reader.Read());
601

  
602
 0
      throw new JsonSerializationException("Unexpected end when deserializing object.");
603
 10018
    }
604

  
605
    private object CreateAndPopulateList(JsonReader reader, string reference, JsonArrayContract contract)
606
    {
607
 20079
      return CollectionUtils.CreateAndPopulateList(contract.CreatedType, (l, isTemporaryListReference) =>
608
 20079
        {
609
 20079
          if (reference != null && isTemporaryListReference)
610
 1
            throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
611
 20079

  
612
 20079
#if !PocketPC
613
 20078
          if (contract.OnSerializing != null && isTemporaryListReference)
614
 0
            throw new JsonSerializationException("Cannot call OnSerializing on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
615
 20079
#endif
616
 20078
          if (contract.OnError != null && isTemporaryListReference)
617
 0
            throw new JsonSerializationException("Cannot call OnError on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
618
 20079

  
619
 20078
          PopulateList(contract.CreateWrapper(l), reader, reference, contract);
620
 20079
        });
621
 20075
    }
622

  
623
    private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, string reference, JsonArrayContract contract)
624
    {
625
 20089
      object list = wrappedList.UnderlyingCollection;
626

  
627
 20089
      if (reference != null)
628
 4
        Serializer.ReferenceResolver.AddReference(reference, list);
629

  
630
 20089
      contract.InvokeOnDeserializing(list, Serializer.Context);
631

  
632
 20089
      int initialDepth = reader.Depth;
633

  
634
 70341
      while (reader.Read())
635
      {
636
 70340
        switch (reader.TokenType)
637
        {
638
          case JsonToken.EndArray:
639
 20086
            contract.InvokeOnDeserialized(list, Serializer.Context);
640

  
641
 20086
            return wrappedList.UnderlyingCollection;
642
          case JsonToken.Comment:
643
 5
            break;
644
          default:
645
            try
646
            {
647
 50249
              object value = CreateValueNonProperty(reader, contract.CollectionItemType, GetContractSafe(contract.CollectionItemType));
648

  
649
 50237
              wrappedList.Add(value);
650
            }
651
 13
            catch (Exception ex)
652
            {
653
 13
              if (IsErrorHandled(list, contract, wrappedList.Count, ex))
654
 11
                HandleError(reader, initialDepth);
655
              else
656
 2
                throw;
657
            }
658
 50247
            break;
659
        }
660
      }
661

  
662
 0
      throw new JsonSerializationException("Unexpected end when deserializing array.");
663
 20086
    }
664

  
665
#if !SILVERLIGHT && !PocketPC
666
    private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, string id)
667
    {
668
 1
      Type objectType = contract.UnderlyingType;
669

  
670
 1
      SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, GetFormatterConverter());
671

  
672
 1
      bool exit = false;
673
      do
674
      {
675
 19
        switch (reader.TokenType)
676
        {
677
          case JsonToken.PropertyName:
678
 18
            string memberName = reader.Value.ToString();
679
 18
            if (!reader.Read())
680
 0
              throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
681

  
682
 18
            serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
683
 18
            break;
684
          case JsonToken.EndObject:
685
 1
            exit = true;
686
 1
            break;
687
          default:
688
 0
            throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
689
        }
690
 19
      } while (!exit && reader.Read());
691

  
692
 1
      if (contract.ISerializableCreator == null)
693
 0
        throw new JsonSerializationException("ISerializable type '{0}' does not have a valid constructor.".FormatWith(CultureInfo.InvariantCulture, objectType));
694

  
695
 1
      object createdObject = contract.ISerializableCreator(serializationInfo, Serializer.Context);
696

  
697
 1
      if (id != null)
698
 0
        Serializer.ReferenceResolver.AddReference(id, createdObject);
699

  
700
 1
      contract.InvokeOnDeserializing(createdObject, Serializer.Context);
701
 1
      contract.InvokeOnDeserialized(createdObject, Serializer.Context);
702

  
703
 1
      return createdObject;
704
 1
    }
705
#endif
706

  
707
    private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, string id)
708
    {
709
 40233
      object newObject = null;
710

  
711
 40233
      if (contract.UnderlyingType.IsInterface || contract.UnderlyingType.IsAbstract)
712
 1
        throw new JsonSerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
713

  
714
 40232
      if (contract.DefaultCreator != null &&
715
 40232
        (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
716
      {
717
 40217
        newObject = contract.DefaultCreator();
718
      }
719

  
720
 40232
      if (newObject != null)
721
      {
722
 40217
        PopulateObject(newObject, reader, contract, id);
723
 40206
        return newObject;
724
      }
725

  
726
 15
      return CreateObjectFromNonDefaultConstructor(reader, contract, id);
727
 40218
    }
728

  
729
    private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, string id)
730
    {
731
 15
      Type objectType = contract.UnderlyingType;
732

  
733
 15
      if (contract.ParametrizedConstructor == null)
734
 2
        throw new JsonSerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor or only one constructor with arguments.".FormatWith(CultureInfo.InvariantCulture, objectType));
735

  
736
      // create a dictionary to put retrieved values into
737
 13
      IDictionary<JsonProperty, object> propertyValues = contract.Properties.Where(p => !p.Ignored).ToDictionary(kv => kv, kv => (object)null);
738

  
739
 13
      bool exit = false;
740
      do
741
      {
742
 42
        switch (reader.TokenType)
743
        {
744
          case JsonToken.PropertyName:
745
 29
            string memberName = reader.Value.ToString();
746
 29
            if (!reader.Read())
747
 0
              throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
748

  
749
            // attempt exact case match first
750
            // then try match ignoring case
751
 29
            JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
752

  
753
 29
            if (property != null)
754
            {
755
 28
              if (!property.Ignored)
756
 27
                propertyValues[property] = CreateValueProperty(reader, property, null, true, null);
757
              else
758
 1
                reader.Skip();
759
            }
760
            else
761
            {
762
 1
              if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
763
 0
                throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
764

  
765
 1
              reader.Skip();
766
            }
767
 29
            break;
768
          case JsonToken.EndObject:
769
 13
            exit = true;
770
 13
            break;
771
          default:
772
 0
            throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
773
        }
774
 42
      } while (!exit && reader.Read());
775

  
776
 13
      IDictionary<ParameterInfo, object> constructorParameters = contract.ParametrizedConstructor.GetParameters().ToDictionary(p => p, p => (object)null);
777
 13
      IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
778

  
779
 13
      foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
780
      {
781
 28
        ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.PropertyName).Key;
782
 28
        if (matchingConstructorParameter != null)
783
 20
          constructorParameters[matchingConstructorParameter] = propertyValue.Value;
784
        else
785
 8
          remainingPropertyValues.Add(propertyValue);
786
      }
787

  
788
 13
      object createdObject = contract.ParametrizedConstructor.Invoke(constructorParameters.Values.ToArray());
789

  
790
 12
      if (id != null)
791
 0
        Serializer.ReferenceResolver.AddReference(id, createdObject);
792

  
793
 12
      contract.InvokeOnDeserializing(createdObject, Serializer.Context);
794

  
795
      // go through unused values and set the newly created object's properties
796
 6
      foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues)
797
      {
798
 6
        JsonProperty property = remainingPropertyValue.Key;
799
 6
        object value = remainingPropertyValue.Value;
800

  
801
 6
        if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value))
802
 6
          property.ValueProvider.SetValue(createdObject, value);
803
      }
804

  
805
 12
      contract.InvokeOnDeserialized(createdObject, Serializer.Context);
806
 12
      return createdObject;
807
 12
    }
808

  
809
    private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, string id)
810
    {
811
 40229
      contract.InvokeOnDeserializing(newObject, Serializer.Context);
812

  
813
 40229
      Dictionary<JsonProperty, RequiredValue> requiredProperties =
814
 18
        contract.Properties.Where(m => m.Required != Required.Default).ToDictionary(m => m, m => RequiredValue.None);
815

  
816
 40229
      if (id != null)
817
 26
        Serializer.ReferenceResolver.AddReference(id, newObject);
818

  
819
 40229
      int initialDepth = reader.Depth;
820

  
821
      do
822
      {
823
 200881
        switch (reader.TokenType)
824
        {
825
          case JsonToken.PropertyName:
826
 160657
            string memberName = reader.Value.ToString();
827

  
828
            // attempt exact case match first
829
            // then try match ignoring case
830
 160657
            JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
831

  
832
 160657
            if (property == null)
833
            {
834
 38
              if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
835
 2
                throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
836

  
837
 36
              reader.Skip();
838
 36
              continue;
839
            }
840

  
841
 160619
            if (property.PropertyType == typeof(byte[]))
842
            {
843
 6
              reader.ReadAsBytes();
844
            }
845
            else
846
            {
847
 160613
              if (!reader.Read())
848
 0
                throw new JsonSerializationException(
849
 0
                  "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
850
            }
851

  
852
 160619
            SetRequiredProperty(reader, property, requiredProperties);
853

  
854
            try
855
            {
856
 160619
              SetPropertyValue(property, reader, newObject);
857
            }
858
 8
            catch (Exception ex)
859
            {
860
 8
              if (IsErrorHandled(newObject, contract, memberName, ex))
861
 1
                HandleError(reader, initialDepth);
862
              else
863
 7
                throw;
864
            }
865
 160612
            break;
866
          case JsonToken.EndObject:
867
 40220
            foreach (KeyValuePair<JsonProperty, RequiredValue> requiredProperty in requiredProperties)
868
            {
869
 160606
              if (requiredProperty.Value == RequiredValue.None)
870
 1
                throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName));
871
 160605
              if (requiredProperty.Key.Required == Required.Always && requiredProperty.Value == RequiredValue.Null)
872
 1
                throw new JsonSerializationException("Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName));
873
            }
874

  
875
 40218
            contract.InvokeOnDeserialized(newObject, Serializer.Context);
876
 40218
            return newObject;
877
          case JsonToken.Comment:
878
            // ignore
879
 4
            break;
880
          default:
881
 0
            throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
882
        }
883
 160652
      } while (reader.Read());
884

  
885
 0
      throw new JsonSerializationException("Unexpected end when deserializing object.");
886
 40218
    }
887

  
888
    private void SetRequiredProperty(JsonReader reader, JsonProperty property, Dictionary<JsonProperty, RequiredValue> requiredProperties)
889
    {
890
 160619
      if (property != null)
891
      {
892
 160619
        requiredProperties[property] = (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.Undefined)
893
 160619
          ? RequiredValue.Null
894
 160619
          : RequiredValue.Value;
895
      }
896
 160619
    }
897

  
898
    private void HandleError(JsonReader reader, int initialDepth)
899
    {
900
 12
      ClearErrorContext();
901

  
902
 12
      reader.Skip();
903

  
904
 21
      while (reader.Depth > (initialDepth + 1))
905
      {
906
 9
        reader.Read();
907
      }
908
 12
    }
909

  
910
    internal enum RequiredValue
911
    {
912
      None,
913
      Null,
914
      Value
915
    }
916
  }
917
}