Json.NET
Code Coverage Statistics for Source File

Newtonsoft.Json\Serialization\DefaultContractResolver.cs

Symbol Coverage: 92.28% (239 of 259)

Branch Coverage: 89.95% (170 of 189)

Cyclomatic Complexity Avg: 3.38 Max:22

Code Lines: 281


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.ComponentModel;
30
using System.Globalization;
31
using System.Linq;
32
using System.Reflection;
33
using System.Runtime.Serialization;
34
using System.Security.Permissions;
35
using Newtonsoft.Json.Converters;
36
using Newtonsoft.Json.Utilities;
37
using Newtonsoft.Json.Linq;
38

  
39
namespace Newtonsoft.Json.Serialization
40
{
41
  internal struct ResolverContractKey : IEquatable<ResolverContractKey>
42
  {
43
    private readonly Type _resolverType;
44
    private readonly Type _contractType;
45

  
46
    public ResolverContractKey(Type resolverType, Type contractType)
47
    {
48
 794021
      _resolverType = resolverType;
49
 794021
      _contractType = contractType;
50
 794021
    }
51

  
52
    public override int GetHashCode()
53
    {
54
 839783
      return _resolverType.GetHashCode() ^ _contractType.GetHashCode();
55
 839783
    }
56

  
57
    public override bool Equals(object obj)
58
    {
59
 0
      if (!(obj is ResolverContractKey))
60
 0
        return false;
61

  
62
 0
      return Equals((ResolverContractKey) obj);
63
 0
    }
64

  
65
    public bool Equals(ResolverContractKey other)
66
    {
67
 794071
      return (_resolverType == other._resolverType && _contractType == other._contractType);
68
 794071
    }
69
  }
70

  
71
  /// <summary>
72
  /// Used by <see cref="JsonSerializer"/> to resolves a <see cref="JsonContract"/> for a given <see cref="Type"/>.
73
  /// </summary>
74
  public class DefaultContractResolver : IContractResolver
75
  {
76
 1
    internal static readonly IContractResolver Instance = new DefaultContractResolver(true);
77
 1
    private static readonly IList<JsonConverter> BuiltInConverters = new List<JsonConverter>
78
 1
      {
79
 1
#if !PocketPC && !SILVERLIGHT && !NET20
80
 1
        new EntityKeyMemberConverter(),
81
 1
#endif
82
 1
        new BinaryConverter(),
83
 1
        new KeyValuePairConverter(),
84
 1
#if !SILVERLIGHT
85
 1
        new XmlNodeConverter(),
86
 1
        new DataSetConverter(),
87
 1
        new DataTableConverter(),
88
 1
#endif
89
 1
        new BsonObjectIdConverter()
90
 1
      };
91

  
92
    private static Dictionary<ResolverContractKey, JsonContract> _sharedContractCache;
93
 1
    private static readonly object _typeContractCacheLock = new object();
94

  
95
    private Dictionary<ResolverContractKey, JsonContract> _instanceContractCache;
96
    private readonly bool _sharedCache;
97

  
98
    /// <summary>
99
    /// Gets a value indicating whether members are being get and set using dynamic code generation.
100
    /// This value is determined by the runtime permissions available.
101
    /// </summary>
102
    /// <value>
103
    /// 	<c>true</c> if using dynamic code generation; otherwise, <c>false</c>.
104
    /// </value>
105
    public bool DynamicCodeGeneration
106
    {
107
 598
      get { return JsonTypeReflector.DynamicCodeGeneration; }
108
    }
109

  
110
    /// <summary>
111
    /// Gets or sets the default members search flags.
112
    /// </summary>
113
    /// <value>The default members search flags.</value>
114
    public BindingFlags DefaultMembersSearchFlags { get; set; }
115

  
116
    /// <summary>
117
    /// Initializes a new instance of the <see cref="DefaultContractResolver"/> class.
118
    /// </summary>
119
 0
    public DefaultContractResolver()
120
 0
      : this(false)
121
    {
122
 0
    }
123

  
124
    /// <summary>
125
    /// Initializes a new instance of the <see cref="DefaultContractResolver"/> class.
126
    /// </summary>
127
    /// <param name="shareCache">
128
    /// if set to <c>true</c> the <see cref="IContractResolver"/> will use a cached shared with other resolvers of the same type.
129
    /// This will improve significantly performance for unshared resolvers but cause unexpected behavior if instances of the resolver could produce different results.
130
    /// </param>
131
 12
    public DefaultContractResolver(bool shareCache)
132
    {
133
 12
      DefaultMembersSearchFlags = BindingFlags.Public | BindingFlags.Instance;
134
 12
      _sharedCache = shareCache;
135
 12
    }
136

  
137
    private Dictionary<ResolverContractKey, JsonContract> GetCache()
138
    {
139
 794329
      if (_sharedCache)
140
 794316
        return _sharedContractCache;
141
      else
142
 13
        return _instanceContractCache;
143
 794329
    }
144

  
145
    private void UpdateCache(Dictionary<ResolverContractKey, JsonContract> cache)
146
    {
147
 308
      if (_sharedCache)
148
 302
        _sharedContractCache = cache;
149
      else
150
 6
        _instanceContractCache = cache;
151
 308
    }
152

  
153
    /// <summary>
154
    /// Resolves the contract for a given type.
155
    /// </summary>
156
    /// <param name="type">The type to resolve a contract for.</param>
157
    /// <returns>The contract for a given type.</returns>
158
    public virtual JsonContract ResolveContract(Type type)
159
    {
160
 794021
      if (type == null)
161
 0
        throw new ArgumentNullException("type");
162

  
163
      JsonContract contract;
164
 794021
      ResolverContractKey key = new ResolverContractKey(GetType(), type);
165
 794021
      Dictionary<ResolverContractKey, JsonContract> cache = GetCache();
166
 794021
      if (cache == null || !cache.TryGetValue(key, out contract))
167
      {
168
 310
        contract = CreateContract(type);
169

  
170
        // avoid the possibility of modifying the cache dictionary while another thread is accessing it
171
 308
        lock (_typeContractCacheLock)
172
        {
173
 308
          cache = GetCache();
174
 308
          Dictionary<ResolverContractKey, JsonContract> updatedCache =
175
 308
            (cache != null)
176
 308
              ? new Dictionary<ResolverContractKey, JsonContract>(cache)
177
 308
              : new Dictionary<ResolverContractKey, JsonContract>();
178
 308
          updatedCache[key] = contract;
179

  
180
 308
          UpdateCache(updatedCache);
181
        }
182
      }
183

  
184
 794019
      return contract;
185
 794019
    }
186

  
187
    /// <summary>
188
    /// Gets the serializable members for the type.
189
    /// </summary>
190
    /// <param name="objectType">The type to get serializable members for.</param>
191
    /// <returns>The serializable members for the type.</returns>
192
    protected virtual List<MemberInfo> GetSerializableMembers(Type objectType)
193
    {
194
#if !PocketPC && !NET20
195
 173
      DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(objectType);
196
#endif
197

  
198
 173
      List<MemberInfo> defaultMembers = ReflectionUtils.GetFieldsAndProperties(objectType, DefaultMembersSearchFlags)
199
 173
        .Where(m => !ReflectionUtils.IsIndexedProperty(m)).ToList();
200
 173
      List<MemberInfo> allMembers = ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
201
 173
        .Where(m => !ReflectionUtils.IsIndexedProperty(m)).ToList();
202

  
203
 173
      List<MemberInfo> serializableMembers = new List<MemberInfo>();
204
 173
      foreach (MemberInfo member in allMembers)
205
      {
206
 1140
        if (defaultMembers.Contains(member))
207
        {
208
          // add all members that are found by default member search
209
 579
          serializableMembers.Add(member);
210
        }
211
        else
212
        {
213
          // add members that are explicitly marked with JsonProperty/DataMember attribute
214
 561
          if (JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member) != null)
215
 18
            serializableMembers.Add(member);
216
#if !PocketPC && !NET20
217
 543
          else if (dataContractAttribute != null && JsonTypeReflector.GetAttribute<DataMemberAttribute>(member) != null)
218
 3
            serializableMembers.Add(member);
219
#endif
220
        }
221
      }
222

  
223
#if !PocketPC && !SILVERLIGHT && !NET20
224
      Type match;
225
      // don't include EntityKey on entities objects... this is a bit hacky
226
 173
      if (objectType.AssignableToTypeName("System.Data.Objects.DataClasses.EntityObject", out match))
227
 2
        serializableMembers = serializableMembers.Where(ShouldSerializeEntityMember).ToList();
228
#endif
229

  
230
 173
      return serializableMembers;
231
 173
    }
232

  
233
#if !PocketPC && !SILVERLIGHT && !NET20
234
    private bool ShouldSerializeEntityMember(MemberInfo memberInfo)
235
    {
236
 18
      PropertyInfo propertyInfo = memberInfo as PropertyInfo;
237
 18
      if (propertyInfo != null)
238
      {
239
 18
        if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition().FullName == "System.Data.Objects.DataClasses.EntityReference`1")
240
 2
          return false;
241
      }
242

  
243
 16
      return true;
244
 18
    }
245
#endif
246

  
247
    /// <summary>
248
    /// Creates a <see cref="JsonObjectContract"/> for the given type.
249
    /// </summary>
250
    /// <param name="objectType">Type of the object.</param>
251
    /// <returns>A <see cref="JsonObjectContract"/> for the given type.</returns>
252
    protected virtual JsonObjectContract CreateObjectContract(Type objectType)
253
    {
254
 174
      JsonObjectContract contract = new JsonObjectContract(objectType);
255
 174
      InitializeContract(contract);
256

  
257
 173
      contract.MemberSerialization = JsonTypeReflector.GetObjectMemberSerialization(objectType);
258
 173
      contract.Properties.AddRange(CreateProperties(contract));
259
 172
      if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic)
260
 29
        contract.ParametrizedConstructor = GetParametrizedConstructor(objectType);
261

  
262
 172
      return contract;
263
 172
    }
264

  
265
    private ConstructorInfo GetParametrizedConstructor(Type objectType)
266
    {
267
 29
      ConstructorInfo[] constructors = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
268

  
269
 29
      if (constructors.Length == 1)
270
 20
        return constructors[0];
271
      else
272
 9
        return null;
273
 29
    }
274

  
275
    /// <summary>
276
    /// Resolves the default <see cref="JsonConverter" /> for the contract.
277
    /// </summary>
278
    /// <param name="objectType">Type of the object.</param>
279
    /// <returns></returns>
280
    protected virtual JsonConverter ResolveContractConverter(Type objectType)
281
    {
282
 310
      return JsonTypeReflector.GetJsonConverter(objectType, objectType);
283
 309
    }
284

  
285
    private Func<object> GetDefaultCreator(Type createdType)
286
    {
287
 255
      return JsonTypeReflector.ReflectionDelegateFactory.CreateDefaultConstructor<object>(createdType);
288
 255
    }
289

  
290
    private void InitializeContract(JsonContract contract)
291
    {
292
 310
      JsonContainerAttribute containerAttribute = JsonTypeReflector.GetJsonContainerAttribute(contract.UnderlyingType);
293
 310
      if (containerAttribute != null)
294
      {
295
 13
        contract.IsReference = containerAttribute._isReference;
296
      }
297
#if !PocketPC && !NET20
298
      else
299
      {
300
 297
        DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(contract.UnderlyingType);
301
        // doesn't have a null value
302
 297
        if (dataContractAttribute != null && dataContractAttribute.IsReference)
303
 3
          contract.IsReference = true;
304
      }
305
#endif
306

  
307
 310
      contract.Converter = ResolveContractConverter(contract.UnderlyingType);
308

  
309
      // then see whether object is compadible with any of the built in converters
310
 309
      contract.InternalConverter = JsonSerializer.GetMatchingConverter(BuiltInConverters, contract.UnderlyingType);
311

  
312
 309
      if (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true)
313
 309
        || contract.CreatedType.IsValueType)
314
      {
315
 255
        contract.DefaultCreator = GetDefaultCreator(contract.CreatedType);
316

  
317
 255
        contract.DefaultCreatorNonPublic = (!contract.CreatedType.IsValueType &&
318
 255
                                            ReflectionUtils.GetDefaultConstructor(contract.CreatedType) == null);
319
      }
320

  
321
 309
      foreach (MethodInfo method in contract.UnderlyingType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
322
      {
323
        // compact framework errors when getting parameters for a generic method
324
        // lame, but generic methods should not be callbacks anyway
325
 5961
        if (method.ContainsGenericParameters)
326
 23
          continue;
327

  
328
 5938
        Type prevAttributeType = null;
329
 5938
        ParameterInfo[] parameters = method.GetParameters();
330

  
331
#if !PocketPC && !NET20
332
 5938
        if (IsValidCallback(method, parameters, typeof(OnSerializingAttribute), contract.OnSerializing, ref prevAttributeType))
333
        {
334
 6
          contract.OnSerializing = method;
335
        }
336
 5938
        if (IsValidCallback(method, parameters, typeof(OnSerializedAttribute), contract.OnSerialized, ref prevAttributeType))
337
        {
338
 4
          contract.OnSerialized = method;
339
        }
340
 5938
        if (IsValidCallback(method, parameters, typeof(OnDeserializingAttribute), contract.OnDeserializing, ref prevAttributeType))
341
        {
342
 6
          contract.OnDeserializing = method;
343
        }
344
 5938
        if (IsValidCallback(method, parameters, typeof(OnDeserializedAttribute), contract.OnDeserialized, ref prevAttributeType))
345
        {
346
 6
          contract.OnDeserialized = method;
347
        }
348
#endif
349
 5938
        if (IsValidCallback(method, parameters, typeof(OnErrorAttribute), contract.OnError, ref prevAttributeType))
350
        {
351
 5
          contract.OnError = method;
352
        }
353
      }
354
 309
    }
355

  
356
    /// <summary>
357
    /// Creates a <see cref="JsonDictionaryContract"/> for the given type.
358
    /// </summary>
359
    /// <param name="objectType">Type of the object.</param>
360
    /// <returns>A <see cref="JsonDictionaryContract"/> for the given type.</returns>
361
    protected virtual JsonDictionaryContract CreateDictionaryContract(Type objectType)
362
    {
363
 16
      JsonDictionaryContract contract = new JsonDictionaryContract(objectType);
364
 16
      InitializeContract(contract);
365

  
366
 16
      return contract;
367
 16
    }
368

  
369
    /// <summary>
370
    /// Creates a <see cref="JsonArrayContract"/> for the given type.
371
    /// </summary>
372
    /// <param name="objectType">Type of the object.</param>
373
    /// <returns>A <see cref="JsonArrayContract"/> for the given type.</returns>
374
    protected virtual JsonArrayContract CreateArrayContract(Type objectType)
375
    {
376
 60
      JsonArrayContract contract = new JsonArrayContract(objectType);
377
 60
      InitializeContract(contract);
378

  
379
 60
      return contract;
380
 60
    }
381

  
382
    /// <summary>
383
    /// Creates a <see cref="JsonPrimitiveContract"/> for the given type.
384
    /// </summary>
385
    /// <param name="objectType">Type of the object.</param>
386
    /// <returns>A <see cref="JsonPrimitiveContract"/> for the given type.</returns>
387
    protected virtual JsonPrimitiveContract CreatePrimitiveContract(Type objectType)
388
    {
389
 45
      JsonPrimitiveContract contract = new JsonPrimitiveContract(objectType);
390
 45
      InitializeContract(contract);
391
      
392
 45
      return contract;
393
 45
    }
394

  
395
    /// <summary>
396
    /// Creates a <see cref="JsonLinqContract"/> for the given type.
397
    /// </summary>
398
    /// <param name="objectType">Type of the object.</param>
399
    /// <returns>A <see cref="JsonLinqContract"/> for the given type.</returns>
400
    protected virtual JsonLinqContract CreateLinqContract(Type objectType)
401
    {
402
 3
      JsonLinqContract contract = new JsonLinqContract(objectType);
403
 3
      InitializeContract(contract);
404

  
405
 3
      return contract;
406
 3
    }
407

  
408
#if !SILVERLIGHT && !PocketPC
409
    /// <summary>
410
    /// Creates a <see cref="JsonISerializableContract"/> for the given type.
411
    /// </summary>
412
    /// <param name="objectType">Type of the object.</param>
413
    /// <returns>A <see cref="JsonISerializableContract"/> for the given type.</returns>
414
    protected virtual JsonISerializableContract CreateISerializableContract(Type objectType)
415
    {
416
 5
      JsonISerializableContract contract = new JsonISerializableContract(objectType);
417
 5
      InitializeContract(contract);
418

  
419
 5
      ConstructorInfo constructorInfo = objectType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new [] {typeof (SerializationInfo), typeof (StreamingContext)}, null);
420
 5
      if (constructorInfo != null)
421
      {
422
 5
        MethodCall<object, object> methodCall = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(constructorInfo);
423

  
424
 1
        contract.ISerializableCreator = (args => methodCall(null, args));
425
      }
426

  
427
 5
      return contract;
428
 5
    }
429
#endif
430

  
431
    /// <summary>
432
    /// Creates a <see cref="JsonStringContract"/> for the given type.
433
    /// </summary>
434
    /// <param name="objectType">Type of the object.</param>
435
    /// <returns>A <see cref="JsonStringContract"/> for the given type.</returns>
436
    protected virtual JsonStringContract CreateStringContract(Type objectType)
437
    {
438
 7
      JsonStringContract contract = new JsonStringContract(objectType);
439
 7
      InitializeContract(contract);
440

  
441
 7
      return contract;
442
 7
    }
443

  
444
    /// <summary>
445
    /// Determines which contract type is created for the given type.
446
    /// </summary>
447
    /// <param name="objectType">Type of the object.</param>
448
    /// <returns>A <see cref="JsonContract"/> for the given type.</returns>
449
    protected virtual JsonContract CreateContract(Type objectType)
450
    {
451
 309
      if (JsonConvert.IsJsonPrimitiveType(objectType))
452
 45
        return CreatePrimitiveContract(objectType);
453

  
454
 264
      if (JsonTypeReflector.GetJsonObjectAttribute(objectType) != null)
455
 13
        return CreateObjectContract(objectType);
456

  
457
 251
      if (JsonTypeReflector.GetJsonArrayAttribute(objectType) != null)
458
 0
        return CreateArrayContract(objectType);
459

  
460
 251
      if (objectType.IsSubclassOf(typeof(JToken)))
461
 3
        return CreateLinqContract(objectType);
462

  
463
 248
      if (CollectionUtils.IsDictionaryType(objectType))
464
 16
        return CreateDictionaryContract(objectType);
465

  
466
 232
      if (typeof(IEnumerable).IsAssignableFrom(objectType))
467
 60
        return CreateArrayContract(objectType);
468

  
469
 172
      if (CanConvertToString(objectType))
470
 7
        return CreateStringContract(objectType);
471

  
472
#if !SILVERLIGHT && !PocketPC
473
 165
      if (typeof(ISerializable).IsAssignableFrom(objectType))
474
 5
        return CreateISerializableContract(objectType);
475
#endif
476

  
477
 160
      return CreateObjectContract(objectType);
478
 307
    }
479

  
480
    internal static bool CanConvertToString(Type type)
481
    {
482
#if !PocketPC
483
 172
      TypeConverter converter = ConvertUtils.GetConverter(type);
484

  
485
      // use the objectType's TypeConverter if it has one and can convert to a string
486
 172
      if (converter != null
487
 172
#if !SILVERLIGHT
488
 172
 && !(converter is ComponentConverter)
489
 172
 && !(converter is ReferenceConverter)
490
 172
#endif
491
 172
 && converter.GetType() != typeof(TypeConverter))
492
      {
493
 5
        if (converter.CanConvertTo(typeof(string)))
494
 5
          return true;
495
      }
496
#endif
497

  
498
 167
      if (type == typeof(Type) || type.IsSubclassOf(typeof(Type)))
499
 2
        return true;
500

  
501
#if SILVERLIGHT || PocketPC
502
      if (type == typeof(Guid) || type == typeof(Uri) || type == typeof(TimeSpan))
503
        return true;
504
#endif
505

  
506
 165
      return false;
507
 172
    }
508

  
509
    private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType)
510
    {
511
 29690
      if (!method.IsDefined(attributeType, false))
512
 29663
        return false;
513

  
514
 27
      if (currentCallback != null)
515
 0
        throw new Exception("Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'.".FormatWith(CultureInfo.InvariantCulture, method, currentCallback, GetClrTypeFullName(method.DeclaringType), attributeType));
516

  
517
 27
      if (prevAttributeType != null)
518
 0
        throw new Exception("Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType), method));
519

  
520
 27
      if (method.IsVirtual)
521
 0
        throw new Exception("Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType), attributeType));
522

  
523
 27
      if (method.ReturnType != typeof(void))
524
 0
        throw new Exception("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method));
525

  
526
 27
      if (attributeType == typeof(OnErrorAttribute))
527
      {
528
 5
        if (parameters == null || parameters.Length != 2 || parameters[0].ParameterType != typeof(StreamingContext) || parameters[1].ParameterType != typeof(ErrorContext))
529
 0
          throw new Exception("Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof (StreamingContext), typeof(ErrorContext)));
530
      }
531
      else
532
      {
533
 22
        if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext))
534
 0
          throw new Exception("Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType), method, typeof(StreamingContext)));
535
      }
536

  
537
 27
      prevAttributeType = attributeType;
538

  
539
 27
      return true;
540
 29690
    }
541

  
542
    internal static string GetClrTypeFullName(Type type)
543
    {
544
 0
      if (type.IsGenericTypeDefinition || !type.ContainsGenericParameters)
545
 0
        return type.FullName;
546

  
547
 0
      return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[] { type.Namespace, type.Name });
548
 0
    }
549

  
550
    /// <summary>
551
    /// Creates properties for the given <see cref="JsonObjectContract"/>.
552
    /// </summary>
553
    /// <param name="contract">The contract to create properties for.</param>
554
    /// <returns>Properties for the given <see cref="JsonObjectContract"/>.</returns>
555
    protected virtual IList<JsonProperty> CreateProperties(JsonObjectContract contract)
556
    {
557
 173
      List<MemberInfo> members = GetSerializableMembers(contract.UnderlyingType);
558
 173
      if (members == null)
559
 0
        throw new JsonSerializationException("Null collection of seralizable members returned.");
560

  
561
 173
      JsonPropertyCollection properties = new JsonPropertyCollection(contract);
562

  
563
 173
      foreach (MemberInfo member in members)
564
      {
565
 598
        JsonProperty property = CreateProperty(contract, member);
566

  
567
 598
        if (property != null)
568
 598
          properties.AddProperty(property);
569
      }
570

  
571
 172
      return properties;
572
 172
    }
573

  
574
    /// <summary>
575
    /// Creates the <see cref="IValueProvider"/> used by the serializer to get and set values from a member.
576
    /// </summary>
577
    /// <param name="member">The member.</param>
578
    /// <returns>The <see cref="IValueProvider"/> used by the serializer to get and set values from a member.</returns>
579
    protected virtual IValueProvider CreateMemberValueProvider(MemberInfo member)
580
    {
581
#if !PocketPC && !SILVERLIGHT
582
 598
      if (DynamicCodeGeneration)
583
 598
        return new DynamicValueProvider(member);
584
#endif
585

  
586
 0
      return new ReflectionValueProvider(member);
587
 598
    }
588

  
589
    /// <summary>
590
    /// Creates a <see cref="JsonProperty"/> for the given <see cref="MemberInfo"/>.
591
    /// </summary>
592
    /// <param name="contract">The member's declaring types <see cref="JsonObjectContract"/>.</param>
593
    /// <param name="member">The member to create a <see cref="JsonProperty"/> for.</param>
594
    /// <returns>A created <see cref="JsonProperty"/> for the given <see cref="MemberInfo"/>.</returns>
595
    protected virtual JsonProperty CreateProperty(JsonObjectContract contract, MemberInfo member)
596
    {
597
 598
      JsonProperty property = new JsonProperty();
598
 598
      property.PropertyType = ReflectionUtils.GetMemberUnderlyingType(member);
599
 598
      property.ValueProvider = CreateMemberValueProvider(member);
600
      
601
      // resolve converter for property
602
      // the class type might have a converter but the property converter takes presidence
603
 598
      property.Converter = JsonTypeReflector.GetJsonConverter(member, property.PropertyType);
604

  
605
#if !PocketPC && !NET20
606
 598
      DataContractAttribute dataContractAttribute = JsonTypeReflector.GetDataContractAttribute(member.DeclaringType);
607

  
608
      DataMemberAttribute dataMemberAttribute;
609
 598
      if (dataContractAttribute != null)
610
 46
        dataMemberAttribute = JsonTypeReflector.GetAttribute<DataMemberAttribute>(member);
611
      else
612
 552
        dataMemberAttribute = null;
613
#endif
614

  
615
 598
      JsonPropertyAttribute propertyAttribute = JsonTypeReflector.GetAttribute<JsonPropertyAttribute>(member);
616
 598
      bool hasIgnoreAttribute = (JsonTypeReflector.GetAttribute<JsonIgnoreAttribute>(member) != null);
617

  
618
      string mappedName;
619
 598
      if (propertyAttribute != null && propertyAttribute.PropertyName != null)
620
 18
        mappedName = propertyAttribute.PropertyName;
621
#if !PocketPC && !NET20
622
 580
      else if (dataMemberAttribute != null && dataMemberAttribute.Name != null)
623
 2
        mappedName = dataMemberAttribute.Name;
624
#endif
625
      else
626
 578
        mappedName = member.Name;
627

  
628
 598
      property.PropertyName = ResolvePropertyName(mappedName);
629

  
630
 598
      if (propertyAttribute != null)
631
 73
        property.Required = propertyAttribute.Required;
632
#if !PocketPC && !NET20
633
 525
      else if (dataMemberAttribute != null)
634
 38
        property.Required = (dataMemberAttribute.IsRequired) ? Required.AllowNull : Required.Default;
635
#endif
636
      else
637
 487
        property.Required = Required.Default;
638

  
639
 598
      property.Ignored = (hasIgnoreAttribute ||
640
 598
                      (contract.MemberSerialization == MemberSerialization.OptIn
641
 598
                       && propertyAttribute == null
642
 598
#if !PocketPC && !NET20
643
 598
                       && dataMemberAttribute == null
644
 598
#endif
645
 598
));
646

  
647
 598
      bool allowNonPublicAccess = false;
648
 598
      if ((DefaultMembersSearchFlags & BindingFlags.NonPublic) == BindingFlags.NonPublic)
649
 3
        allowNonPublicAccess = true;
650
 598
      if (propertyAttribute != null)
651
 73
        allowNonPublicAccess = true;
652
#if !PocketPC && !NET20
653
 598
      if (dataMemberAttribute != null)
654
 39
        allowNonPublicAccess = true;
655
#endif
656

  
657
 598
      property.Readable = ReflectionUtils.CanReadMemberValue(member, allowNonPublicAccess);
658
 598
      property.Writable = ReflectionUtils.CanSetMemberValue(member, allowNonPublicAccess);
659

  
660
 598
      property.MemberConverter = JsonTypeReflector.GetJsonConverter(member, ReflectionUtils.GetMemberUnderlyingType(member));
661

  
662
 598
      DefaultValueAttribute defaultValueAttribute = JsonTypeReflector.GetAttribute<DefaultValueAttribute>(member);
663
 598
      property.DefaultValue = (defaultValueAttribute != null) ? defaultValueAttribute.Value : null;
664

  
665
 598
      property.NullValueHandling = (propertyAttribute != null) ? propertyAttribute._nullValueHandling : null;
666
 598
      property.DefaultValueHandling = (propertyAttribute != null) ? propertyAttribute._defaultValueHandling : null;
667
 598
      property.ReferenceLoopHandling = (propertyAttribute != null) ? propertyAttribute._referenceLoopHandling : null;
668
 598
      property.ObjectCreationHandling = (propertyAttribute != null) ? propertyAttribute._objectCreationHandling : null;
669
 598
      property.TypeNameHandling = (propertyAttribute != null) ? propertyAttribute._typeNameHandling : null;
670
 598
      property.IsReference = (propertyAttribute != null) ? propertyAttribute._isReference : null;
671

  
672
 598
      property.ShouldSerialize = CreateShouldSerializeTest(member);
673

  
674
 598
      return property;
675
 598
    }
676

  
677
    private Predicate<object> CreateShouldSerializeTest(MemberInfo member)
678
    {
679
 598
      MethodInfo shouldSerializeMethod = member.DeclaringType.GetMethod(JsonTypeReflector.ShouldSerializePrefix + member.Name, new Type[0]);
680

  
681
 598
      if (shouldSerializeMethod == null || shouldSerializeMethod.ReturnType != typeof(bool))
682
 596
        return null;
683

  
684
 2
      MethodCall<object, object> shouldSerializeCall =
685
 2
        JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(shouldSerializeMethod);
686

  
687
 2
      return o => (bool) shouldSerializeCall(o);
688
 598
    }
689

  
690
    /// <summary>
691
    /// Resolves the name of the property.
692
    /// </summary>
693
    /// <param name="propertyName">Name of the property.</param>
694
    /// <returns>Name of the property.</returns>
695
    protected virtual string ResolvePropertyName(string propertyName)
696
    {
697
 577
      return propertyName;
698
 577
    }
699
  }
700
}