~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/Newtonsoft.Json/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
31
using System.ComponentModel;
 
32
using System.Dynamic;
 
33
#endif
 
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;
 
40
#if NET20
 
41
using Newtonsoft.Json.Utilities.LinqBridge;
 
42
#else
 
43
using System.Linq;
 
44
#endif
 
45
 
 
46
namespace Newtonsoft.Json.Serialization
 
47
{
 
48
  internal class JsonSerializerInternalReader : JsonSerializerInternalBase
 
49
  {
 
50
    internal enum PropertyPresence
 
51
    {
 
52
      None,
 
53
      Null,
 
54
      Value
 
55
    }
 
56
 
 
57
    private JsonSerializerProxy _internalSerializer;
 
58
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
59
    private JsonFormatterConverter _formatterConverter;
 
60
#endif
 
61
 
 
62
    public JsonSerializerInternalReader(JsonSerializer serializer)
 
63
      : base(serializer)
 
64
    {
 
65
    }
 
66
 
 
67
    public void Populate(JsonReader reader, object target)
 
68
    {
 
69
      ValidationUtils.ArgumentNotNull(target, "target");
 
70
 
 
71
      Type objectType = target.GetType();
 
72
 
 
73
      JsonContract contract = Serializer.ContractResolver.ResolveContract(objectType);
 
74
 
 
75
      if (reader.TokenType == JsonToken.None)
 
76
        reader.Read();
 
77
 
 
78
      if (reader.TokenType == JsonToken.StartArray)
 
79
      {
 
80
        if (contract.ContractType == JsonContractType.Array)
 
81
          PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, (JsonArrayContract) contract, null, null);
 
82
        else
 
83
          throw JsonSerializationException.Create(reader, "Cannot populate JSON array onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
 
84
      }
 
85
      else if (reader.TokenType == JsonToken.StartObject)
 
86
      {
 
87
        CheckedRead(reader);
 
88
 
 
89
        string id = null;
 
90
        if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
 
91
        {
 
92
          CheckedRead(reader);
 
93
          id = (reader.Value != null) ? reader.Value.ToString() : null;
 
94
          CheckedRead(reader);
 
95
        }
 
96
 
 
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);
 
101
        else
 
102
          throw JsonSerializationException.Create(reader, "Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
 
103
      }
 
104
      else
 
105
      {
 
106
        throw JsonSerializationException.Create(reader, "Unexpected initial token '{0}' when populating object. Expected JSON object or array.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
 
107
      }
 
108
    }
 
109
 
 
110
    private JsonContract GetContractSafe(Type type)
 
111
    {
 
112
      if (type == null)
 
113
        return null;
 
114
 
 
115
      return Serializer.ContractResolver.ResolveContract(type);
 
116
    }
 
117
 
 
118
    public object Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
 
119
    {
 
120
      if (reader == null)
 
121
        throw new ArgumentNullException("reader");
 
122
 
 
123
      JsonContract contract = GetContractSafe(objectType);
 
124
 
 
125
      try
 
126
      {
 
127
        JsonConverter converter = GetConverter(contract, null, null, null);
 
128
 
 
129
        if (reader.TokenType == JsonToken.None && !ReadForType(reader, contract, converter != null))
 
130
        {
 
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));
 
133
 
 
134
          return null;
 
135
        }
 
136
 
 
137
        object deserializedValue;
 
138
 
 
139
        if (converter != null && converter.CanRead)
 
140
          deserializedValue = DeserializeConvertable(converter, reader, objectType, null);
 
141
        else
 
142
          deserializedValue = CreateValueInternal(reader, objectType, contract, null, null, null, null);
 
143
 
 
144
        if (checkAdditionalContent)
 
145
        {
 
146
          if (reader.Read() && reader.TokenType != JsonToken.Comment)
 
147
            throw new JsonSerializationException("Additional text found in JSON string after finishing deserializing object.");
 
148
        }
 
149
 
 
150
        return deserializedValue;
 
151
      }
 
152
      catch (Exception ex)
 
153
      {
 
154
        if (IsErrorHandled(null, contract, null, reader as IJsonLineInfo, reader.Path, ex))
 
155
        {
 
156
          HandleError(reader, false, 0);
 
157
          return null;
 
158
        }
 
159
        else
 
160
        {
 
161
          throw;
 
162
        }
 
163
      }
 
164
    }
 
165
 
 
166
    private JsonSerializerProxy GetInternalSerializer()
 
167
    {
 
168
      if (_internalSerializer == null)
 
169
        _internalSerializer = new JsonSerializerProxy(this);
 
170
 
 
171
      return _internalSerializer;
 
172
    }
 
173
 
 
174
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
175
    private JsonFormatterConverter GetFormatterConverter()
 
176
    {
 
177
      if (_formatterConverter == null)
 
178
        _formatterConverter = new JsonFormatterConverter(GetInternalSerializer());
 
179
 
 
180
      return _formatterConverter;
 
181
    }
 
182
#endif
 
183
 
 
184
    private JToken CreateJToken(JsonReader reader, JsonContract contract)
 
185
    {
 
186
      ValidationUtils.ArgumentNotNull(reader, "reader");
 
187
 
 
188
      if (contract != null && contract.UnderlyingType == typeof (JRaw))
 
189
      {
 
190
        return JRaw.Create(reader);
 
191
      }
 
192
      else
 
193
      {
 
194
        JToken token;
 
195
        using (JTokenWriter writer = new JTokenWriter())
 
196
        {
 
197
          writer.WriteToken(reader);
 
198
          token = writer.Token;
 
199
        }
 
200
 
 
201
        return token;
 
202
      }
 
203
    }
 
204
 
 
205
    private JToken CreateJObject(JsonReader reader)
 
206
    {
 
207
      ValidationUtils.ArgumentNotNull(reader, "reader");
 
208
 
 
209
      // this is needed because we've already read inside the object, looking for special properties
 
210
      JToken token;
 
211
      using (JTokenWriter writer = new JTokenWriter())
 
212
      {
 
213
        writer.WriteStartObject();
 
214
 
 
215
        if (reader.TokenType == JsonToken.PropertyName)
 
216
          writer.WriteToken(reader, reader.Depth - 1);
 
217
        else
 
218
          writer.WriteEndObject();
 
219
 
 
220
        token = writer.Token;
 
221
      }
 
222
 
 
223
      return token;
 
224
    }
 
225
 
 
226
    private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
 
227
    {
 
228
      if (contract != null && contract.ContractType == JsonContractType.Linq)
 
229
        return CreateJToken(reader, contract);
 
230
 
 
231
      do
 
232
      {
 
233
        switch (reader.TokenType)
 
234
        {
 
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:
 
244
          case JsonToken.Date:
 
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)
 
250
              return null;
 
251
 
 
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);
 
255
 
 
256
            return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
 
257
          case JsonToken.StartConstructor:
 
258
            string constructorName = reader.Value.ToString();
 
259
 
 
260
            return EnsureType(reader, constructorName, CultureInfo.InvariantCulture, contract, objectType);
 
261
          case JsonToken.Null:
 
262
          case JsonToken.Undefined:
 
263
#if !(NETFX_CORE || PORTABLE)
 
264
            if (objectType == typeof (DBNull))
 
265
              return DBNull.Value;
 
266
#endif
 
267
 
 
268
            return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
 
269
          case JsonToken.Raw:
 
270
            return new JRaw((string) reader.Value);
 
271
          case JsonToken.Comment:
 
272
            // ignore
 
273
            break;
 
274
          default:
 
275
            throw JsonSerializationException.Create(reader, "Unexpected token while deserializing object: " + reader.TokenType);
 
276
        }
 
277
      } while (reader.Read());
 
278
 
 
279
      throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
 
280
    }
 
281
 
 
282
    internal string GetExpectedDescription(JsonContract contract)
 
283
    {
 
284
      switch (contract.ContractType)
 
285
      {
 
286
        case JsonContractType.Object:
 
287
        case JsonContractType.Dictionary:
 
288
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
289
        case JsonContractType.Serializable:
 
290
#endif
 
291
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
292
        case JsonContractType.Dynamic:
 
293
#endif
 
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";
 
301
        default:
 
302
          throw new ArgumentOutOfRangeException();
 
303
      }
 
304
    }
 
305
 
 
306
    private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract, JsonProperty containerProperty)
 
307
    {
 
308
      JsonConverter converter = null;
 
309
      if (memberConverter != null)
 
310
      {
 
311
        // member attribute converter
 
312
        converter = memberConverter;
 
313
      }
 
314
      else if (containerProperty != null && containerProperty.ItemConverter != null)
 
315
      {
 
316
        converter = containerProperty.ItemConverter;
 
317
      }
 
318
      else if (containerContract != null && containerContract.ItemConverter != null)
 
319
      {
 
320
        converter = containerContract.ItemConverter;
 
321
      }
 
322
      else if (contract != null)
 
323
      {
 
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;
 
334
      }
 
335
      return converter;
 
336
    }
 
337
 
 
338
    private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
 
339
    {
 
340
      CheckedRead(reader);
 
341
 
 
342
      string id;
 
343
      object newValue;
 
344
      if (ReadSpecialProperties(reader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
 
345
        return newValue;
 
346
 
 
347
      if (!HasDefinedType(objectType))
 
348
        return CreateJObject(reader);
 
349
 
 
350
      if (contract == null)
 
351
        throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
 
352
 
 
353
      switch (contract.ContractType)
 
354
      {
 
355
        case JsonContractType.Object:
 
356
          bool createdFromNonDefaultConstructor = false;
 
357
          JsonObjectContract objectContract = (JsonObjectContract) contract;
 
358
          object targetObject;
 
359
          if (existingValue != null)
 
360
            targetObject = existingValue;
 
361
          else
 
362
            targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultConstructor);
 
363
 
 
364
          // don't populate if read from non-default constructor because the object has already been read
 
365
          if (createdFromNonDefaultConstructor)
 
366
            return targetObject;
 
367
 
 
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))
 
373
          {
 
374
            CheckedRead(reader);
 
375
            object value = CreateValueInternal(reader, objectType, primitiveContract, member, null, null, existingValue);
 
376
 
 
377
            CheckedRead(reader);
 
378
            return value;
 
379
          }
 
380
          break;
 
381
        case JsonContractType.Dictionary:
 
382
          JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) contract;
 
383
          object targetDictionary;
 
384
          if (existingValue != null)
 
385
            targetDictionary = existingValue;
 
386
          else
 
387
            targetDictionary = CreateNewDictionary(reader, dictionaryContract);
 
388
 
 
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);
 
394
#endif
 
395
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
396
        case JsonContractType.Serializable:
 
397
          JsonISerializableContract serializableContract = (JsonISerializableContract) contract;
 
398
          return CreateISerializable(reader, serializableContract, id);
 
399
#endif
 
400
      }
 
401
 
 
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)));
 
405
    }
 
406
 
 
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)
 
408
    {
 
409
      id = null;
 
410
      newValue = null;
 
411
 
 
412
      if (reader.TokenType == JsonToken.PropertyName)
 
413
      {
 
414
        string propertyName = reader.Value.ToString();
 
415
 
 
416
        if (propertyName.Length > 0 && propertyName[0] == '$')
 
417
        {
 
418
          // read 'special' properties
 
419
          // $type, $id, $ref, etc
 
420
          bool specialProperty;
 
421
 
 
422
          do
 
423
          {
 
424
            propertyName = reader.Value.ToString();
 
425
 
 
426
            if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
 
427
            {
 
428
              CheckedRead(reader);
 
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));
 
431
 
 
432
              string reference = (reader.Value != null) ? reader.Value.ToString() : null;
 
433
 
 
434
              CheckedRead(reader);
 
435
 
 
436
              if (reference != null)
 
437
              {
 
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));
 
440
 
 
441
                newValue = Serializer.ReferenceResolver.ResolveReference(this, reference);
 
442
 
 
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);
 
445
 
 
446
                return true;
 
447
              }
 
448
              else
 
449
              {
 
450
                specialProperty = true;
 
451
              }
 
452
            }
 
453
            else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
 
454
            {
 
455
              CheckedRead(reader);
 
456
              string qualifiedTypeName = reader.Value.ToString();
 
457
 
 
458
              TypeNameHandling resolvedTypeNameHandling =
 
459
                ((member != null) ? member.TypeNameHandling : null)
 
460
                ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
 
461
                ?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null)
 
462
                ?? Serializer.TypeNameHandling;
 
463
 
 
464
              if (resolvedTypeNameHandling != TypeNameHandling.None)
 
465
              {
 
466
                string typeName;
 
467
                string assemblyName;
 
468
                ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);
 
469
 
 
470
                Type specifiedType;
 
471
                try
 
472
                {
 
473
                  specifiedType = Serializer.Binder.BindToType(assemblyName, typeName);
 
474
                }
 
475
                catch (Exception ex)
 
476
                {
 
477
                  throw JsonSerializationException.Create(reader, "Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
 
478
                }
 
479
 
 
480
                if (specifiedType == null)
 
481
                  throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
 
482
 
 
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);
 
485
 
 
486
                if (objectType != null
 
487
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
488
                    && objectType != typeof (IDynamicMetaObjectProvider)
 
489
#endif
 
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));
 
492
 
 
493
                objectType = specifiedType;
 
494
                contract = GetContractSafe(specifiedType);
 
495
              }
 
496
 
 
497
              CheckedRead(reader);
 
498
 
 
499
              specialProperty = true;
 
500
            }
 
501
            else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
 
502
            {
 
503
              CheckedRead(reader);
 
504
 
 
505
              id = (reader.Value != null) ? reader.Value.ToString() : null;
 
506
 
 
507
              CheckedRead(reader);
 
508
              specialProperty = true;
 
509
            }
 
510
            else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
 
511
            {
 
512
              CheckedRead(reader);
 
513
              object list = CreateList(reader, objectType, contract, member, existingValue, id);
 
514
              CheckedRead(reader);
 
515
              newValue = list;
 
516
              return true;
 
517
            }
 
518
            else
 
519
            {
 
520
              specialProperty = false;
 
521
            }
 
522
          } while (specialProperty
 
523
                   && reader.TokenType == JsonToken.PropertyName);
 
524
        }
 
525
      }
 
526
      return false;
 
527
    }
 
528
 
 
529
    private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)
 
530
    {
 
531
      if (contract == null)
 
532
        throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
 
533
 
 
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)));
 
539
 
 
540
      return arrayContract;
 
541
    }
 
542
 
 
543
    private void CheckedRead(JsonReader reader)
 
544
    {
 
545
      if (!reader.Read())
 
546
        throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
 
547
    }
 
548
 
 
549
    private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id)
 
550
    {
 
551
      object value;
 
552
      if (HasDefinedType(objectType))
 
553
      {
 
554
        JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract);
 
555
 
 
556
        if (existingValue == null)
 
557
        {
 
558
          bool isTemporaryListReference;
 
559
          IList list = CollectionUtils.CreateList(contract.CreatedType, out isTemporaryListReference);
 
560
 
 
561
          if (id != null && isTemporaryListReference)
 
562
            throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
 
563
 
 
564
#if !PocketPC
 
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));
 
567
#endif
 
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));
 
570
 
 
571
          if (!arrayContract.IsMultidimensionalArray)
 
572
            PopulateList(arrayContract.CreateWrapper(list), reader, arrayContract, member, id);
 
573
          else
 
574
            PopulateMultidimensionalArray(list, reader, arrayContract, member, id);
 
575
 
 
576
          // create readonly and fixed sized collections using the temporary list
 
577
          if (isTemporaryListReference)
 
578
          {
 
579
            if (arrayContract.IsMultidimensionalArray)
 
580
            {
 
581
              list = CollectionUtils.ToMultidimensionalArray(list, ReflectionUtils.GetCollectionItemType(contract.CreatedType), contract.CreatedType.GetArrayRank());
 
582
            }
 
583
            else if (contract.CreatedType.IsArray)
 
584
            {
 
585
              list = CollectionUtils.ToArray(((List<object>) list).ToArray(), ReflectionUtils.GetCollectionItemType(contract.CreatedType));
 
586
            }
 
587
            else if (ReflectionUtils.InheritsGenericDefinition(contract.CreatedType, typeof(ReadOnlyCollection<>)))
 
588
            {
 
589
              list = (IList) ReflectionUtils.CreateInstance(contract.CreatedType, list);
 
590
            }
 
591
          }
 
592
          else if (list is IWrappedCollection)
 
593
          {
 
594
            return ((IWrappedCollection)list).UnderlyingCollection;
 
595
          }
 
596
 
 
597
          value = list;
 
598
        }
 
599
        else
 
600
        {
 
601
          value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, arrayContract, member, id);
 
602
        }
 
603
      }
 
604
      else
 
605
      {
 
606
        value = CreateJToken(reader, contract);
 
607
      }
 
608
      return value;
 
609
    }
 
610
 
 
611
    private bool HasDefinedType(Type type)
 
612
    {
 
613
      return (type != null && type != typeof (object) && !typeof (JToken).IsSubclassOf(type)
 
614
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
615
        && type != typeof (IDynamicMetaObjectProvider)
 
616
#endif
 
617
        );
 
618
    }
 
619
 
 
620
    private object EnsureType(JsonReader reader, object value, CultureInfo culture, JsonContract contract, Type targetType)
 
621
    {
 
622
      if (targetType == null)
 
623
        return value;
 
624
 
 
625
      Type valueType = ReflectionUtils.GetObjectType(value);
 
626
 
 
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)
 
630
      {
 
631
        try
 
632
        {
 
633
          if (value == null && contract.IsNullable)
 
634
            return null;
 
635
 
 
636
          if (contract.IsConvertable)
 
637
          {
 
638
            if (contract.NonNullableUnderlyingType.IsEnum())
 
639
              {
 
640
                if (value is string)
 
641
                  return Enum.Parse(contract.NonNullableUnderlyingType, value.ToString(), true);
 
642
                else if (ConvertUtils.IsInteger(value))
 
643
                  return Enum.ToObject(contract.NonNullableUnderlyingType, value);
 
644
              }
 
645
 
 
646
              return Convert.ChangeType(value, contract.NonNullableUnderlyingType, culture);
 
647
          }
 
648
 
 
649
          return ConvertUtils.ConvertOrCast(value, culture, contract.NonNullableUnderlyingType);
 
650
        }
 
651
        catch (Exception ex)
 
652
        {
 
653
          throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, FormatValueForPrint(value), targetType), ex);
 
654
        }
 
655
      }
 
656
 
 
657
      return value;
 
658
    }
 
659
 
 
660
    private string FormatValueForPrint(object value)
 
661
    {
 
662
      if (value == null)
 
663
        return "{null}";
 
664
 
 
665
      if (value is string)
 
666
        return @"""" + value + @"""";
 
667
 
 
668
      return value.ToString();
 
669
    }
 
670
 
 
671
    private void SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
 
672
    {
 
673
      object currentValue;
 
674
      bool useExistingValue;
 
675
      JsonContract propertyContract;
 
676
      bool gottenCurrentValue;
 
677
 
 
678
      if (CalculatePropertyDetails(property, ref propertyConverter, containerContract, containerProperty, reader, target, out useExistingValue, out currentValue, out propertyContract, out gottenCurrentValue))
 
679
        return;
 
680
 
 
681
      object value;
 
682
 
 
683
      if (propertyConverter != null && propertyConverter.CanRead)
 
684
      {
 
685
        if (!gottenCurrentValue && target != null && property.Readable)
 
686
          currentValue = property.ValueProvider.GetValue(target);
 
687
 
 
688
        value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, currentValue);
 
689
      }
 
690
      else
 
691
      {
 
692
        value = CreateValueInternal(reader, property.PropertyType, propertyContract, property, containerContract, containerProperty, (useExistingValue) ? currentValue : null);
 
693
      }
 
694
 
 
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))
 
700
      {
 
701
        property.ValueProvider.SetValue(target, value);
 
702
 
 
703
        if (property.SetIsSpecified != null)
 
704
        {
 
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);
 
707
 
 
708
          property.SetIsSpecified(target, true);
 
709
        }
 
710
      }
 
711
    }
 
712
 
 
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)
 
714
    {
 
715
      currentValue = null;
 
716
      useExistingValue = false;
 
717
      propertyContract = null;
 
718
      gottenCurrentValue = false;
 
719
 
 
720
      if (property.Ignored)
 
721
      {
 
722
        reader.Skip();
 
723
        return true;
 
724
      }
 
725
 
 
726
      ObjectCreationHandling objectCreationHandling =
 
727
        property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
 
728
 
 
729
      if ((objectCreationHandling == ObjectCreationHandling.Auto || objectCreationHandling == ObjectCreationHandling.Reuse)
 
730
          && (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
 
731
          && property.Readable)
 
732
      {
 
733
        currentValue = property.ValueProvider.GetValue(target);
 
734
        gottenCurrentValue = true;
 
735
 
 
736
        useExistingValue = (currentValue != null
 
737
                            && !property.PropertyType.IsArray
 
738
                            && !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof (ReadOnlyCollection<>))
 
739
                            && !property.PropertyType.IsValueType());
 
740
      }
 
741
 
 
742
      if (!property.Writable && !useExistingValue)
 
743
      {
 
744
        reader.Skip();
 
745
        return true;
 
746
      }
 
747
 
 
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)
 
750
      {
 
751
        reader.Skip();
 
752
        return true;
 
753
      }
 
754
 
 
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()))
 
759
      {
 
760
        reader.Skip();
 
761
        return true;
 
762
      }
 
763
 
 
764
      if (property.PropertyContract == null)
 
765
        property.PropertyContract = GetContractSafe(property.PropertyType);
 
766
 
 
767
      if (currentValue == null)
 
768
      {
 
769
        propertyContract = property.PropertyContract;
 
770
      }
 
771
      else
 
772
      {
 
773
        propertyContract = GetContractSafe(currentValue.GetType());
 
774
 
 
775
        if (propertyContract != property.PropertyContract)
 
776
          propertyConverter = GetConverter(propertyContract, property.MemberConverter, containerContract, containerProperty);
 
777
      }
 
778
 
 
779
      return false;
 
780
    }
 
781
 
 
782
    private void AddReference(JsonReader reader, string id, object value)
 
783
    {
 
784
      try
 
785
      {
 
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);
 
788
 
 
789
        Serializer.ReferenceResolver.AddReference(this, id, value);
 
790
      }
 
791
      catch (Exception ex)
 
792
      {
 
793
        throw JsonSerializationException.Create(reader, "Error reading object reference '{0}'.".FormatWith(CultureInfo.InvariantCulture, id), ex);
 
794
      }
 
795
    }
 
796
 
 
797
    private bool HasFlag(DefaultValueHandling value, DefaultValueHandling flag)
 
798
    {
 
799
      return ((value & flag) == flag);
 
800
    }
 
801
 
 
802
    private bool ShouldSetPropertyValue(JsonProperty property, object value)
 
803
    {
 
804
      if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && value == null)
 
805
        return false;
 
806
 
 
807
      if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore)
 
808
        && MiscellaneousUtils.ValueEquals(value, property.GetResolvedDefaultValue()))
 
809
        return false;
 
810
 
 
811
      if (!property.Writable)
 
812
        return false;
 
813
 
 
814
      return true;
 
815
    }
 
816
 
 
817
    public object CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract)
 
818
    {
 
819
      object dictionary;
 
820
 
 
821
      if (contract.DefaultCreator != null &&
 
822
        (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
 
823
        dictionary = contract.DefaultCreator();
 
824
      else
 
825
        throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
 
826
 
 
827
      return dictionary;
 
828
    }
 
829
 
 
830
    private void OnDeserializing(JsonReader reader, JsonContract contract, object value)
 
831
    {
 
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);
 
834
 
 
835
      contract.InvokeOnDeserializing(value, Serializer.Context);
 
836
    }
 
837
 
 
838
    private void OnDeserialized(JsonReader reader, JsonContract contract, object value)
 
839
    {
 
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);
 
842
 
 
843
      contract.InvokeOnDeserialized(value, Serializer.Context);
 
844
    }
 
845
 
 
846
    private object PopulateDictionary(IWrappedDictionary wrappedDictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id)
 
847
    {
 
848
      object dictionary = wrappedDictionary.UnderlyingDictionary;
 
849
 
 
850
      if (id != null)
 
851
        AddReference(reader, id, dictionary);
 
852
 
 
853
      OnDeserializing(reader, contract, dictionary);
 
854
 
 
855
      int initialDepth = reader.Depth;
 
856
 
 
857
      if (contract.KeyContract == null)
 
858
        contract.KeyContract = GetContractSafe(contract.DictionaryKeyType);
 
859
 
 
860
      if (contract.ItemContract == null)
 
861
        contract.ItemContract = GetContractSafe(contract.DictionaryValueType);
 
862
 
 
863
      JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty);
 
864
 
 
865
      bool finished = false;
 
866
      do
 
867
      {
 
868
        switch (reader.TokenType)
 
869
        {
 
870
          case JsonToken.PropertyName:
 
871
            object keyValue = reader.Value;
 
872
            try
 
873
            {
 
874
              try
 
875
              {
 
876
                keyValue = EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType);
 
877
              }
 
878
              catch (Exception ex)
 
879
              {
 
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);
 
881
              }
 
882
 
 
883
              if (!ReadForType(reader, contract.ItemContract, dictionaryValueConverter != null))
 
884
                throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
 
885
 
 
886
              object itemValue;
 
887
              if (dictionaryValueConverter != null && dictionaryValueConverter.CanRead)
 
888
                itemValue = DeserializeConvertable(dictionaryValueConverter, reader, contract.DictionaryValueType, null);
 
889
              else
 
890
                itemValue = CreateValueInternal(reader, contract.DictionaryValueType, contract.ItemContract, null, contract, containerProperty, null);
 
891
 
 
892
              wrappedDictionary[keyValue] = itemValue;
 
893
            }
 
894
            catch (Exception ex)
 
895
            {
 
896
              if (IsErrorHandled(dictionary, contract, keyValue, reader as IJsonLineInfo, reader.Path, ex))
 
897
                HandleError(reader, true, initialDepth);
 
898
              else
 
899
                throw;
 
900
            }
 
901
            break;
 
902
          case JsonToken.Comment:
 
903
            break;
 
904
          case JsonToken.EndObject:
 
905
            finished = true;
 
906
            break;
 
907
          default:
 
908
            throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
 
909
        }
 
910
      } while (!finished && reader.Read());
 
911
 
 
912
      if (!finished)
 
913
        ThrowUnexpectedEndException(reader, contract, dictionary, "Unexpected end when deserializing object.");
 
914
 
 
915
      OnDeserialized(reader, contract, dictionary);
 
916
      return dictionary;
 
917
    }
 
918
 
 
919
    private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
 
920
    {
 
921
      int rank = contract.UnderlyingType.GetArrayRank();
 
922
 
 
923
      if (id != null)
 
924
        AddReference(reader, id, list);
 
925
 
 
926
      OnDeserializing(reader, contract, list);
 
927
 
 
928
      JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
 
929
      JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);
 
930
 
 
931
      int? previousErrorIndex = null;
 
932
      Stack<IList> listStack = new Stack<IList>();
 
933
      listStack.Push(list);
 
934
      IList currentList = list;
 
935
 
 
936
      bool finished = false;
 
937
      do
 
938
      {
 
939
        int initialDepth = reader.Depth;
 
940
 
 
941
        if (listStack.Count == rank)
 
942
        {
 
943
          try
 
944
          {
 
945
            if (ReadForType(reader, collectionItemContract, collectionItemConverter != null))
 
946
            {
 
947
              switch (reader.TokenType)
 
948
              {
 
949
                case JsonToken.EndArray:
 
950
                  listStack.Pop();
 
951
                  currentList = listStack.Peek();
 
952
                  previousErrorIndex = null;
 
953
                  break;
 
954
                case JsonToken.Comment:
 
955
                  break;
 
956
                default:
 
957
                  object value;
 
958
 
 
959
                  if (collectionItemConverter != null && collectionItemConverter.CanRead)
 
960
                    value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
 
961
                  else
 
962
                    value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
 
963
 
 
964
                  currentList.Add(value);
 
965
                  break;
 
966
              }
 
967
            }
 
968
            else
 
969
            {
 
970
              break;
 
971
            }
 
972
          }
 
973
          catch (Exception ex)
 
974
          {
 
975
            JsonPosition errorPosition = reader.GetPosition(initialDepth);
 
976
 
 
977
            if (IsErrorHandled(list, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
 
978
            {
 
979
              HandleError(reader, true, initialDepth);
 
980
 
 
981
              if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
 
982
              {
 
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);
 
986
              }
 
987
              else
 
988
              {
 
989
                previousErrorIndex = errorPosition.Position;
 
990
              }
 
991
            }
 
992
            else
 
993
            {
 
994
              throw;
 
995
            }
 
996
          }
 
997
        }
 
998
        else
 
999
        {
 
1000
          if (reader.Read())
 
1001
          {
 
1002
            switch (reader.TokenType)
 
1003
            {
 
1004
              case JsonToken.StartArray:
 
1005
                IList newList = new List<object>();
 
1006
                currentList.Add(newList);
 
1007
                listStack.Push(newList);
 
1008
                currentList = newList;
 
1009
                break;
 
1010
              case JsonToken.EndArray:
 
1011
                listStack.Pop();
 
1012
 
 
1013
                if (listStack.Count > 0)
 
1014
                {
 
1015
                  currentList = listStack.Peek();
 
1016
                }
 
1017
                else
 
1018
                {
 
1019
                  finished = true;
 
1020
                }
 
1021
                break;
 
1022
              case JsonToken.Comment:
 
1023
                break;
 
1024
              default:
 
1025
                throw JsonSerializationException.Create(reader, "Unexpected token when deserializing multidimensional array: " + reader.TokenType);
 
1026
            }
 
1027
          }
 
1028
          else
 
1029
          {
 
1030
            break;
 
1031
          }
 
1032
        }
 
1033
      } while (!finished);
 
1034
 
 
1035
      if (!finished)
 
1036
        ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
 
1037
 
 
1038
      OnDeserialized(reader, contract, list);
 
1039
      return list;
 
1040
    }
 
1041
 
 
1042
    private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object currentObject, string message)
 
1043
    {
 
1044
      try
 
1045
      {
 
1046
        throw JsonSerializationException.Create(reader, message);
 
1047
      }
 
1048
      catch (Exception ex)
 
1049
      {
 
1050
        if (IsErrorHandled(currentObject, contract, null, reader as IJsonLineInfo, reader.Path, ex))
 
1051
          HandleError(reader, false, 0);
 
1052
        else
 
1053
          throw;
 
1054
      }
 
1055
    }
 
1056
 
 
1057
    private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
 
1058
    {
 
1059
      object list = wrappedList.UnderlyingCollection;
 
1060
 
 
1061
      if (id != null)
 
1062
        AddReference(reader, id, list);
 
1063
 
 
1064
      // can't populate an existing array
 
1065
      if (wrappedList.IsFixedSize)
 
1066
      {
 
1067
        reader.Skip();
 
1068
        return list;
 
1069
      }
 
1070
 
 
1071
      OnDeserializing(reader, contract, list);
 
1072
 
 
1073
      int initialDepth = reader.Depth;
 
1074
 
 
1075
      JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
 
1076
      JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);
 
1077
 
 
1078
      int? previousErrorIndex = null;
 
1079
 
 
1080
      bool finished = false;
 
1081
      do
 
1082
      {
 
1083
        try
 
1084
        {
 
1085
          if (ReadForType(reader, collectionItemContract, collectionItemConverter != null))
 
1086
          {
 
1087
            switch (reader.TokenType)
 
1088
            {
 
1089
              case JsonToken.EndArray:
 
1090
                finished = true;
 
1091
                break;
 
1092
              case JsonToken.Comment:
 
1093
                break;
 
1094
              default:
 
1095
                object value;
 
1096
 
 
1097
                if (collectionItemConverter != null && collectionItemConverter.CanRead)
 
1098
                  value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
 
1099
                else
 
1100
                  value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
 
1101
 
 
1102
                wrappedList.Add(value);
 
1103
                break;
 
1104
            }
 
1105
          }
 
1106
          else
 
1107
          {
 
1108
            break;
 
1109
          }
 
1110
        }
 
1111
        catch (Exception ex)
 
1112
        {
 
1113
          JsonPosition errorPosition = reader.GetPosition(initialDepth);
 
1114
 
 
1115
          if (IsErrorHandled(list, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
 
1116
          {
 
1117
            HandleError(reader, true, initialDepth);
 
1118
 
 
1119
            if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
 
1120
            {
 
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);
 
1124
            }
 
1125
            else
 
1126
            {
 
1127
              previousErrorIndex = errorPosition.Position;
 
1128
            }
 
1129
          }
 
1130
          else
 
1131
          {
 
1132
            throw;
 
1133
          }
 
1134
        }
 
1135
      } while (!finished);
 
1136
 
 
1137
      if (!finished)
 
1138
        ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
 
1139
 
 
1140
      OnDeserialized(reader, contract, list);
 
1141
      return list;
 
1142
    }
 
1143
 
 
1144
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
1145
    private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, string id)
 
1146
    {
 
1147
      Type objectType = contract.UnderlyingType;
 
1148
 
 
1149
      if (!JsonTypeReflector.FullyTrusted)
 
1150
      {
 
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));
 
1154
      }
 
1155
 
 
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);
 
1158
 
 
1159
      SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, GetFormatterConverter());
 
1160
 
 
1161
      bool finished = false;
 
1162
      do
 
1163
      {
 
1164
        switch (reader.TokenType)
 
1165
        {
 
1166
          case JsonToken.PropertyName:
 
1167
            string memberName = reader.Value.ToString();
 
1168
            if (!reader.Read())
 
1169
              throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
 
1170
 
 
1171
            serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
 
1172
            break;
 
1173
          case JsonToken.Comment:
 
1174
            break;
 
1175
          case JsonToken.EndObject:
 
1176
            finished = true;
 
1177
            break;
 
1178
          default:
 
1179
            throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
 
1180
        }
 
1181
      } while (!finished && reader.Read());
 
1182
 
 
1183
      if (!finished)
 
1184
        ThrowUnexpectedEndException(reader, contract, serializationInfo, "Unexpected end when deserializing object.");
 
1185
 
 
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));
 
1188
 
 
1189
      object createdObject = contract.ISerializableCreator(serializationInfo, Serializer.Context);
 
1190
 
 
1191
      if (id != null)
 
1192
        AddReference(reader, id, createdObject);
 
1193
 
 
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);
 
1197
 
 
1198
      return createdObject;
 
1199
    }
 
1200
#endif
 
1201
 
 
1202
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
1203
    private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, JsonProperty member, string id)
 
1204
    {
 
1205
      IDynamicMetaObjectProvider newObject;
 
1206
 
 
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));
 
1209
 
 
1210
      if (contract.DefaultCreator != null &&
 
1211
        (!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
 
1212
        newObject = (IDynamicMetaObjectProvider) contract.DefaultCreator();
 
1213
      else
 
1214
        throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
 
1215
 
 
1216
      if (id != null)
 
1217
        AddReference(reader, id, newObject);
 
1218
 
 
1219
      OnDeserializing(reader, contract, newObject);
 
1220
 
 
1221
      int initialDepth = reader.Depth;
 
1222
 
 
1223
      bool finished = false;
 
1224
      do
 
1225
      {
 
1226
        switch (reader.TokenType)
 
1227
        {
 
1228
          case JsonToken.PropertyName:
 
1229
            string memberName = reader.Value.ToString();
 
1230
 
 
1231
            try
 
1232
            {
 
1233
              if (!reader.Read())
 
1234
                throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
 
1235
 
 
1236
              // first attempt to find a settable property, otherwise fall back to a dynamic set without type
 
1237
              JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
 
1238
 
 
1239
              if (property != null && property.Writable && !property.Ignored)
 
1240
              {
 
1241
                if (property.PropertyContract == null)
 
1242
                  property.PropertyContract = GetContractSafe(property.PropertyType);
 
1243
 
 
1244
                JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, null, null);
 
1245
 
 
1246
                SetPropertyValue(property, propertyConverter, null, member, reader, newObject);
 
1247
              }
 
1248
              else
 
1249
              {
 
1250
                Type t = (JsonReader.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType : typeof (IDynamicMetaObjectProvider);
 
1251
 
 
1252
                JsonContract dynamicMemberContract = GetContractSafe(t);
 
1253
                JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member);
 
1254
 
 
1255
                object value;
 
1256
                if (dynamicMemberConverter != null && dynamicMemberConverter.CanRead)
 
1257
                  value = DeserializeConvertable(dynamicMemberConverter, reader, t, null);
 
1258
                else
 
1259
                  value = CreateValueInternal(reader, t, dynamicMemberContract, null, null, member, null);
 
1260
 
 
1261
                newObject.TrySetMember(memberName, value);
 
1262
              }
 
1263
            }
 
1264
            catch (Exception ex)
 
1265
            {
 
1266
              if (IsErrorHandled(newObject, contract, memberName, reader as IJsonLineInfo, reader.Path, ex))
 
1267
                HandleError(reader, true, initialDepth);
 
1268
              else
 
1269
                throw;
 
1270
            }
 
1271
            break;
 
1272
          case JsonToken.EndObject:
 
1273
            finished = true;
 
1274
            break;
 
1275
          default:
 
1276
            throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
 
1277
        }
 
1278
      } while (!finished && reader.Read());
 
1279
 
 
1280
      if (!finished)
 
1281
        ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
 
1282
 
 
1283
      OnDeserialized(reader, contract, newObject);
 
1284
 
 
1285
      return newObject;
 
1286
    }
 
1287
#endif
 
1288
 
 
1289
    private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ConstructorInfo constructorInfo, string id)
 
1290
    {
 
1291
      ValidationUtils.ArgumentNotNull(constructorInfo, "constructorInfo");
 
1292
 
 
1293
      Type objectType = contract.UnderlyingType;
 
1294
 
 
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);
 
1297
 
 
1298
      IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndConstructorValues(contract, containerProperty, reader, objectType);
 
1299
 
 
1300
      IDictionary<ParameterInfo, object> constructorParameters = constructorInfo.GetParameters().ToDictionary(p => p, p => (object) null);
 
1301
      IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
 
1302
 
 
1303
      foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
 
1304
      {
 
1305
        ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.UnderlyingName).Key;
 
1306
        if (matchingConstructorParameter != null)
 
1307
          constructorParameters[matchingConstructorParameter] = propertyValue.Value;
 
1308
        else
 
1309
          remainingPropertyValues.Add(propertyValue);
 
1310
      }
 
1311
 
 
1312
      object createdObject = constructorInfo.Invoke(constructorParameters.Values.ToArray());
 
1313
 
 
1314
      if (id != null)
 
1315
        AddReference(reader, id, createdObject);
 
1316
 
 
1317
      OnDeserializing(reader, contract, createdObject);
 
1318
 
 
1319
      // go through unused values and set the newly created object's properties
 
1320
      foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues)
 
1321
      {
 
1322
        JsonProperty property = remainingPropertyValue.Key;
 
1323
        object value = remainingPropertyValue.Value;
 
1324
 
 
1325
        if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value))
 
1326
        {
 
1327
          property.ValueProvider.SetValue(createdObject, value);
 
1328
        }
 
1329
        else if (!property.Writable && value != null)
 
1330
        {
 
1331
          // handle readonly collection/dictionary properties
 
1332
          JsonContract propertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType);
 
1333
 
 
1334
          if (propertyContract.ContractType == JsonContractType.Array)
 
1335
          {
 
1336
            JsonArrayContract propertyArrayContract = (JsonArrayContract)propertyContract;
 
1337
 
 
1338
            object createdObjectCollection = property.ValueProvider.GetValue(createdObject);
 
1339
            if (createdObjectCollection != null)
 
1340
            {
 
1341
              IWrappedCollection createdObjectCollectionWrapper = propertyArrayContract.CreateWrapper(createdObjectCollection);
 
1342
              IWrappedCollection newValues = propertyArrayContract.CreateWrapper(value);
 
1343
 
 
1344
              foreach (object newValue in newValues)
 
1345
              {
 
1346
                createdObjectCollectionWrapper.Add(newValue);
 
1347
              }
 
1348
            }
 
1349
          }
 
1350
          else if (propertyContract.ContractType == JsonContractType.Dictionary)
 
1351
          {
 
1352
            JsonDictionaryContract jsonDictionaryContract = (JsonDictionaryContract)propertyContract;
 
1353
 
 
1354
            object createdObjectDictionary = property.ValueProvider.GetValue(createdObject);
 
1355
            if (createdObjectDictionary != null)
 
1356
            {
 
1357
              IWrappedDictionary createdObjectDictionaryWrapper = jsonDictionaryContract.CreateWrapper(createdObjectDictionary);
 
1358
              IWrappedDictionary newValues = jsonDictionaryContract.CreateWrapper(value);
 
1359
 
 
1360
              foreach (DictionaryEntry newValue in newValues)
 
1361
              {
 
1362
                createdObjectDictionaryWrapper.Add(newValue.Key, newValue.Value);
 
1363
              }
 
1364
            }
 
1365
          }
 
1366
        }
 
1367
      }
 
1368
 
 
1369
      OnDeserialized(reader, contract, createdObject);
 
1370
      return createdObject;
 
1371
    }
 
1372
 
 
1373
    private object DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object existingValue)
 
1374
    {
 
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);
 
1377
 
 
1378
      object value = converter.ReadJson(reader, objectType, existingValue, GetInternalSerializer());
 
1379
 
 
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);
 
1382
 
 
1383
      return value;
 
1384
    }
 
1385
 
 
1386
    private IDictionary<JsonProperty, object> ResolvePropertyAndConstructorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
 
1387
    {
 
1388
      IDictionary<JsonProperty, object> propertyValues = new Dictionary<JsonProperty, object>();
 
1389
      bool exit = false;
 
1390
      do
 
1391
      {
 
1392
        switch (reader.TokenType)
 
1393
        {
 
1394
          case JsonToken.PropertyName:
 
1395
            string memberName = reader.Value.ToString();
 
1396
 
 
1397
            // attempt exact case match first
 
1398
            // then try match ignoring case
 
1399
            JsonProperty property = contract.ConstructorParameters.GetClosestMatchProperty(memberName) ??
 
1400
              contract.Properties.GetClosestMatchProperty(memberName);
 
1401
 
 
1402
            if (property != null)
 
1403
            {
 
1404
              if (property.PropertyContract == null)
 
1405
                property.PropertyContract = GetContractSafe(property.PropertyType);
 
1406
 
 
1407
              JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, containerProperty);
 
1408
 
 
1409
              if (!ReadForType(reader, property.PropertyContract, propertyConverter != null))
 
1410
                throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
 
1411
 
 
1412
              if (!property.Ignored)
 
1413
              {
 
1414
                if (property.PropertyContract == null)
 
1415
                  property.PropertyContract = GetContractSafe(property.PropertyType);
 
1416
 
 
1417
                object propertyValue;
 
1418
                if (propertyConverter != null && propertyConverter.CanRead)
 
1419
                  propertyValue = DeserializeConvertable(propertyConverter, reader, property.PropertyType, null);
 
1420
                else
 
1421
                  propertyValue = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null);
 
1422
 
 
1423
                propertyValues[property] = propertyValue;
 
1424
              }
 
1425
              else
 
1426
              {
 
1427
                reader.Skip();
 
1428
              }
 
1429
            }
 
1430
            else
 
1431
            {
 
1432
              if (!reader.Read())
 
1433
                throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
 
1434
 
 
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);
 
1437
 
 
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));
 
1440
 
 
1441
              reader.Skip();
 
1442
            }
 
1443
            break;
 
1444
          case JsonToken.Comment:
 
1445
            break;
 
1446
          case JsonToken.EndObject:
 
1447
            exit = true;
 
1448
            break;
 
1449
          default:
 
1450
            throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
 
1451
        }
 
1452
      } while (!exit && reader.Read());
 
1453
 
 
1454
      return propertyValues;
 
1455
    }
 
1456
 
 
1457
    private bool ReadForType(JsonReader reader, JsonContract contract, bool hasConverter)
 
1458
    {
 
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
 
1461
      if (hasConverter)
 
1462
        return reader.Read();
 
1463
 
 
1464
      ReadType t = (contract != null) ? contract.InternalReadType : ReadType.Read;
 
1465
 
 
1466
      switch (t)
 
1467
      {
 
1468
        case ReadType.Read:
 
1469
          do
 
1470
          {
 
1471
            if (!reader.Read())
 
1472
              return false;
 
1473
          } while (reader.TokenType == JsonToken.Comment);
 
1474
 
 
1475
          return true;
 
1476
        case ReadType.ReadAsInt32:
 
1477
          reader.ReadAsInt32();
 
1478
          break;
 
1479
        case ReadType.ReadAsDecimal:
 
1480
          reader.ReadAsDecimal();
 
1481
          break;
 
1482
        case ReadType.ReadAsBytes:
 
1483
          reader.ReadAsBytes();
 
1484
          break;
 
1485
        case ReadType.ReadAsString:
 
1486
          reader.ReadAsString();
 
1487
          break;
 
1488
        case ReadType.ReadAsDateTime:
 
1489
          reader.ReadAsDateTime();
 
1490
          break;
 
1491
#if !NET20
 
1492
        case ReadType.ReadAsDateTimeOffset:
 
1493
          reader.ReadAsDateTimeOffset();
 
1494
          break;
 
1495
#endif
 
1496
        default:
 
1497
          throw new ArgumentOutOfRangeException();
 
1498
      }
 
1499
 
 
1500
      return (reader.TokenType != JsonToken.None);
 
1501
    }
 
1502
 
 
1503
    public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultConstructor)
 
1504
    {
 
1505
      object newObject = null;
 
1506
 
 
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));
 
1509
 
 
1510
      if (objectContract.OverrideConstructor != null)
 
1511
      {
 
1512
        if (objectContract.OverrideConstructor.GetParameters().Length > 0)
 
1513
        {
 
1514
          createdFromNonDefaultConstructor = true;
 
1515
          return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.OverrideConstructor, id);
 
1516
        }
 
1517
 
 
1518
        newObject = objectContract.OverrideConstructor.Invoke(null);
 
1519
      }
 
1520
      else if (objectContract.DefaultCreator != null &&
 
1521
        (!objectContract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParametrizedConstructor == null))
 
1522
      {
 
1523
        // use the default constructor if it is...
 
1524
        // public
 
1525
        // non-public and the user has change constructor handling settings
 
1526
        // non-public and there is no other constructor
 
1527
        newObject = objectContract.DefaultCreator();
 
1528
      }
 
1529
      else if (objectContract.ParametrizedConstructor != null)
 
1530
      {
 
1531
        createdFromNonDefaultConstructor = true;
 
1532
        return CreateObjectFromNonDefaultConstructor(reader, objectContract, containerMember, objectContract.ParametrizedConstructor, id);
 
1533
      }
 
1534
 
 
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));
 
1537
 
 
1538
      createdFromNonDefaultConstructor = false;
 
1539
      return newObject;
 
1540
    }
 
1541
 
 
1542
    private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
 
1543
    {
 
1544
      OnDeserializing(reader, contract, newObject);
 
1545
 
 
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)
 
1549
        : null;
 
1550
 
 
1551
      if (id != null)
 
1552
        AddReference(reader, id, newObject);
 
1553
 
 
1554
      int initialDepth = reader.Depth;
 
1555
 
 
1556
      bool finished = false;
 
1557
      do
 
1558
      {
 
1559
        switch (reader.TokenType)
 
1560
        {
 
1561
          case JsonToken.PropertyName:
 
1562
            {
 
1563
              string memberName = reader.Value.ToString();
 
1564
 
 
1565
              try
 
1566
              {
 
1567
                // attempt exact case match first
 
1568
                // then try match ignoring case
 
1569
                JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
 
1570
 
 
1571
                if (property == null)
 
1572
                {
 
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);
 
1575
 
 
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));
 
1578
 
 
1579
                  reader.Skip();
 
1580
                  continue;
 
1581
                }
 
1582
 
 
1583
                if (property.PropertyContract == null)
 
1584
                  property.PropertyContract = GetContractSafe(property.PropertyType);
 
1585
 
 
1586
                JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.MemberConverter, contract, member);
 
1587
 
 
1588
                if (!ReadForType(reader, property.PropertyContract, propertyConverter != null))
 
1589
                  throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
 
1590
 
 
1591
                SetPropertyPresence(reader, property, propertiesPresence);
 
1592
 
 
1593
                SetPropertyValue(property, propertyConverter, contract, member, reader, newObject);
 
1594
              }
 
1595
              catch (Exception ex)
 
1596
              {
 
1597
                if (IsErrorHandled(newObject, contract, memberName, reader as IJsonLineInfo, reader.Path, ex))
 
1598
                  HandleError(reader, true, initialDepth);
 
1599
                else
 
1600
                  throw;
 
1601
              }
 
1602
            }
 
1603
            break;
 
1604
          case JsonToken.EndObject:
 
1605
            finished = true;
 
1606
            break;
 
1607
          case JsonToken.Comment:
 
1608
            // ignore
 
1609
            break;
 
1610
          default:
 
1611
            throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
 
1612
        }
 
1613
      } while (!finished && reader.Read());
 
1614
 
 
1615
      if (!finished)
 
1616
        ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
 
1617
 
 
1618
      EndObject(newObject, reader, contract, initialDepth, propertiesPresence);
 
1619
 
 
1620
      OnDeserialized(reader, contract, newObject);
 
1621
      return newObject;
 
1622
    }
 
1623
 
 
1624
    private void EndObject(object newObject, JsonReader reader, JsonObjectContract contract, int initialDepth, Dictionary<JsonProperty, PropertyPresence> propertiesPresence)
 
1625
    {
 
1626
      if (propertiesPresence != null)
 
1627
      {
 
1628
        foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence)
 
1629
        {
 
1630
          JsonProperty property = propertyPresence.Key;
 
1631
          PropertyPresence presence = propertyPresence.Value;
 
1632
 
 
1633
          if (presence == PropertyPresence.None || presence == PropertyPresence.Null)
 
1634
          {
 
1635
            try
 
1636
            {
 
1637
              Required resolvedRequired = property._required ?? contract.ItemRequired ?? Required.Default;
 
1638
 
 
1639
              switch (presence)
 
1640
              {
 
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));
 
1644
 
 
1645
                  if (property.PropertyContract == null)
 
1646
                    property.PropertyContract = GetContractSafe(property.PropertyType);
 
1647
 
 
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));
 
1650
                  break;
 
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));
 
1654
                  break;
 
1655
              }
 
1656
            }
 
1657
            catch (Exception ex)
 
1658
            {
 
1659
              if (IsErrorHandled(newObject, contract, property.PropertyName, reader as IJsonLineInfo, reader.Path, ex))
 
1660
                HandleError(reader, true, initialDepth);
 
1661
              else
 
1662
                throw;
 
1663
            }
 
1664
          }
 
1665
        }
 
1666
      }
 
1667
    }
 
1668
 
 
1669
    private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dictionary<JsonProperty, PropertyPresence> requiredProperties)
 
1670
    {
 
1671
      if (property != null && requiredProperties != null)
 
1672
      {
 
1673
        requiredProperties[property] = (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.Undefined)
 
1674
          ? PropertyPresence.Null
 
1675
          : PropertyPresence.Value;
 
1676
      }
 
1677
    }
 
1678
 
 
1679
    private void HandleError(JsonReader reader, bool readPastError, int initialDepth)
 
1680
    {
 
1681
      ClearErrorContext();
 
1682
 
 
1683
      if (readPastError)
 
1684
      {
 
1685
        reader.Skip();
 
1686
 
 
1687
        while (reader.Depth > (initialDepth + 1))
 
1688
        {
 
1689
          if (!reader.Read())
 
1690
            break;
 
1691
        }
 
1692
      }
 
1693
    }
 
1694
  }
 
1695
}
 
 
b'\\ No newline at end of file'