Code Coverage Statistics for Source File
Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs
Symbol Coverage: 92.62% (389 of 420)
Branch Coverage: 93.10% (270 of 290)
Cyclomatic Complexity Avg: 5.00 Max:23
Code Lines: 424
Symbol Coverage Trend
View:
L | V | Source |
---|---|---|
1 |
#region License |
|
2 |
// Copyright (c) 2007 James Newton-King |
|
3 |
// |
|
4 |
// Permission is hereby granted, free of charge, to any person |
|
5 |
// obtaining a copy of this software and associated documentation |
|
6 |
// files (the "Software"), to deal in the Software without |
|
7 |
// restriction, including without limitation the rights to use, |
|
8 |
// copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 |
// copies of the Software, and to permit persons to whom the |
|
10 |
// Software is furnished to do so, subject to the following |
|
11 |
// conditions: |
|
12 |
// |
|
13 |
// The above copyright notice and this permission notice shall be |
|
14 |
// included in all copies or substantial portions of the Software. |
|
15 |
// |
|
16 |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
17 |
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
18 |
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
19 |
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
20 |
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
21 |
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
22 |
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
23 |
// OTHER DEALINGS IN THE SOFTWARE. |
|
24 |
#endregion |
|
25 |
||
26 |
using System; |
|
27 |
using System.Collections; |
|
28 |
using System.Collections.Generic; |
|
29 |
using System.Collections.ObjectModel; |
|
30 |
using System.Globalization; |
|
31 |
using System.Linq; |
|
32 |
using System.Reflection; |
|
33 |
using System.Runtime.Serialization; |
|
34 |
using Newtonsoft.Json.Linq; |
|
35 |
using Newtonsoft.Json.Utilities; |
|
36 |
||
37 |
namespace Newtonsoft.Json.Serialization |
|
38 |
{ |
|
39 |
internal class JsonSerializerInternalReader : JsonSerializerInternalBase |
|
40 |
{ |
|
41 |
private JsonSerializerProxy _internalSerializer; |
|
42 |
#if !SILVERLIGHT && !PocketPC |
|
43 |
private JsonFormatterConverter _formatterConverter; |
|
44 |
#endif |
|
45 |
||
46 |
10234 |
public JsonSerializerInternalReader(JsonSerializer serializer) : base(serializer)
|
47 |
{ |
|
48 |
10234 |
}
|
49 |
||
50 |
public void Populate(JsonReader reader, object target) |
|
51 |
{ |
|
52 |
15 |
ValidationUtils.ArgumentNotNull(target, "target");
|
53 |
||
54 |
15 |
Type objectType = target.GetType();
|
55 |
||
56 |
15 |
JsonContract contract = Serializer.ContractResolver.ResolveContract(objectType);
|
57 |
||
58 |
15 |
if (reader.TokenType == JsonToken.None)
|
59 |
12 |
reader.Read();
|
60 |
||
61 |
15 |
if (reader.TokenType == JsonToken.StartArray)
|
62 |
{ |
|
63 |
2 |
if (contract is JsonArrayContract)
|
64 |
1 |
PopulateList(CollectionUtils.CreateCollectionWrapper(target), reader, null, (JsonArrayContract)contract);
|
65 |
else |
|
66 |
1 |
throw new JsonSerializationException("Cannot populate JSON array onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
67 |
} |
|
68 |
13 |
else if (reader.TokenType == JsonToken.StartObject)
|
69 |
{ |
|
70 |
12 |
CheckedRead(reader);
|
71 |
||
72 |
12 |
string id = null;
|
73 |
12 |
if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
|
74 |
{ |
|
75 |
3 |
CheckedRead(reader);
|
76 |
3 |
id = reader.Value.ToString();
|
77 |
3 |
CheckedRead(reader);
|
78 |
} |
|
79 |
||
80 |
12 |
if (contract is JsonDictionaryContract)
|
81 |
1 |
PopulateDictionary(CollectionUtils.CreateDictionaryWrapper(target), reader, (JsonDictionaryContract) contract, id);
|
82 |
11 |
else if (contract is JsonObjectContract)
|
83 |
10 |
PopulateObject(target, reader, (JsonObjectContract) contract, id);
|
84 |
else |
|
85 |
1 |
throw new JsonSerializationException("Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
86 |
} |
|
87 |
else |
|
88 |
{ |
|
89 |
1 |
throw new JsonSerializationException("Unexpected initial token '{0}' when populating object. Expected JSON object or array.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
90 |
} |
|
91 |
12 |
}
|
92 |
||
93 |
private JsonContract GetContractSafe(Type type) |
|
94 |
{ |
|
95 |
251170 |
if (type == null)
|
96 |
20 |
return null;
|
97 |
||
98 |
251150 |
return Serializer.ContractResolver.ResolveContract(type);
|
99 |
251170 |
}
|
100 |
||
101 |
private JsonContract GetContractSafe(Type type, object value) |
|
102 |
{ |
|
103 |
160636 |
if (value == null)
|
104 |
160620 |
return GetContractSafe(type);
|
105 |
||
106 |
16 |
return Serializer.ContractResolver.ResolveContract(value.GetType());
|
107 |
160636 |
}
|
108 |
||
109 |
public object Deserialize(JsonReader reader, Type objectType) |
|
110 |
{ |
|
111 |
10245 |
if (reader == null)
|
112 |
0 |
throw new ArgumentNullException("reader");
|
113 |
||
114 |
10245 |
if (reader.TokenType == JsonToken.None && !reader.Read())
|
115 |
0 |
return null;
|
116 |
||
117 |
10245 |
return CreateValueNonProperty(reader, objectType, GetContractSafe(objectType));
|
118 |
10216 |
}
|
119 |
||
120 |
private JsonSerializerProxy GetInternalSerializer() |
|
121 |
{ |
|
122 |
113 |
if (_internalSerializer == null)
|
123 |
64 |
_internalSerializer = new JsonSerializerProxy(this);
|
124 |
||
125 |
113 |
return _internalSerializer;
|
126 |
113 |
}
|
127 |
||
128 |
#if !SILVERLIGHT && !PocketPC |
|
129 |
private JsonFormatterConverter GetFormatterConverter() |
|
130 |
{ |
|
131 |
1 |
if (_formatterConverter == null)
|
132 |
1 |
_formatterConverter = new JsonFormatterConverter(GetInternalSerializer());
|
133 |
||
134 |
1 |
return _formatterConverter;
|
135 |
1 |
}
|
136 |
#endif |
|
137 |
||
138 |
private JToken CreateJToken(JsonReader reader, JsonContract contract) |
|
139 |
{ |
|
140 |
10 |
ValidationUtils.ArgumentNotNull(reader, "reader");
|
141 |
||
142 |
10 |
if (contract != null && contract.UnderlyingType == typeof(JRaw))
|
143 |
{ |
|
144 |
4 |
return JRaw.Create(reader);
|
145 |
} |
|
146 |
else |
|
147 |
{ |
|
148 |
JToken token; |
|
149 |
6 |
using (JTokenWriter writer = new JTokenWriter())
|
150 |
{ |
|
151 |
6 |
writer.WriteToken(reader);
|
152 |
6 |
token = writer.Token;
|
153 |
} |
|
154 |
||
155 |
6 |
return token;
|
156 |
} |
|
157 |
10 |
}
|
158 |
||
159 |
private JToken CreateJObject(JsonReader reader) |
|
160 |
{ |
|
161 |
9 |
ValidationUtils.ArgumentNotNull(reader, "reader");
|
162 |
||
163 |
// this is needed because we've already read inside the object, looking for special properties |
|
164 |
JToken token; |
|
165 |
9 |
using (JTokenWriter writer = new JTokenWriter())
|
166 |
{ |
|
167 |
9 |
writer.WriteStartObject();
|
168 |
||
169 |
9 |
if (reader.TokenType == JsonToken.PropertyName)
|
170 |
8 |
writer.WriteToken(reader, reader.Depth - 1);
|
171 |
else |
|
172 |
1 |
writer.WriteEndObject();
|
173 |
||
174 |
9 |
token = writer.Token;
|
175 |
} |
|
176 |
||
177 |
9 |
return token;
|
178 |
9 |
}
|
179 |
||
180 |
private object CreateValueProperty(JsonReader reader, JsonProperty property, object target, bool gottenCurrentValue, object currentValue) |
|
181 |
{ |
|
182 |
160636 |
JsonContract contract = GetContractSafe(property.PropertyType, currentValue);
|
183 |
160636 |
Type objectType = property.PropertyType;
|
184 |
||
185 |
160636 |
JsonConverter converter = GetConverter(contract, property.MemberConverter);
|
186 |
||
187 |
160636 |
if (converter != null && converter.CanRead)
|
188 |
{ |
|
189 |
55 |
if (!gottenCurrentValue && target != null && property.Readable)
|
190 |
40 |
currentValue = property.ValueProvider.GetValue(target);
|
191 |
||
192 |
55 |
return converter.ReadJson(reader, objectType, currentValue, GetInternalSerializer());
|
193 |
} |
|
194 |
||
195 |
160581 |
return CreateValueInternal(reader, objectType, contract, property, currentValue);
|
196 |
160631 |
}
|
197 |
||
198 |
private object CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract) |
|
199 |
{ |
|
200 |
90539 |
JsonConverter converter = GetConverter(contract, null);
|
201 |
||
202 |
90539 |
if (converter != null && converter.CanRead)
|
203 |
57 |
return converter.ReadJson(reader, objectType, null, GetInternalSerializer());
|
204 |
||
205 |
90482 |
return CreateValueInternal(reader, objectType, contract, null, null);
|
206 |
90496 |
}
|
207 |
||
208 |
private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue) |
|
209 |
{ |
|
210 |
251063 |
if (contract is JsonLinqContract)
|
211 |
4 |
return CreateJToken(reader, contract);
|
212 |
||
213 |
do |
|
214 |
{ |
|
215 |
251062 |
switch (reader.TokenType)
|
216 |
{ |
|
217 |
// populate a typed object or generic dictionary/array |
|
218 |
// depending upon whether an objectType was supplied |
|
219 |
case JsonToken.StartObject: |
|
220 |
50289 |
return CreateObject(reader, objectType, contract, member, existingValue);
|
221 |
case JsonToken.StartArray: |
|
222 |
20090 |
return CreateList(reader, objectType, contract, member, existingValue, null);
|
223 |
case JsonToken.Integer: |
|
224 |
case JsonToken.Float: |
|
225 |
case JsonToken.Boolean: |
|
226 |
case JsonToken.Date: |
|
227 |
case JsonToken.Bytes: |
|
228 |
80279 |
return EnsureType(reader.Value, objectType);
|
229 |
case JsonToken.String: |
|
230 |
// convert empty string to null automatically for nullable types |
|
231 |
80342 |
if (string.IsNullOrEmpty((string)reader.Value) &&
|
232 |
80342 |
objectType != null &&
|
233 |
80342 |
ReflectionUtils.IsNullableType(objectType))
|
234 |
1 |
return null;
|
235 |
||
236 |
80341 |
return EnsureType(reader.Value, objectType);
|
237 |
case JsonToken.StartConstructor: |
|
238 |
case JsonToken.EndConstructor: |
|
239 |
0 |
string constructorName = reader.Value.ToString();
|
240 |
||
241 |
0 |
return constructorName;
|
242 |
case JsonToken.Null: |
|
243 |
case JsonToken.Undefined: |
|
244 |
20059 |
if (objectType == typeof (DBNull))
|
245 |
1 |
return DBNull.Value;
|
246 |
||
247 |
20058 |
return EnsureType(reader.Value, objectType);
|
248 |
case JsonToken.Raw: |
|
249 |
0 |
return new JRaw((string)reader.Value);
|
250 |
case JsonToken.Comment: |
|
251 |
// ignore |
|
252 |
3 |
break;
|
253 |
default: |
|
254 |
0 |
throw new JsonSerializationException("Unexpected token while deserializing object: " + reader.TokenType);
|
255 |
} |
|
256 |
3 |
} while (reader.Read());
|
257 |
||
258 |
0 |
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
259 |
251030 |
}
|
260 |
||
261 |
private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter) |
|
262 |
{ |
|
263 |
251175 |
JsonConverter converter = null;
|
264 |
251175 |
if (memberConverter != null)
|
265 |
{ |
|
266 |
// member attribute converter |
|
267 |
6 |
converter = memberConverter;
|
268 |
} |
|
269 |
251169 |
else if (contract != null)
|
270 |
{ |
|
271 |
JsonConverter matchingConverter; |
|
272 |
251149 |
if (contract.Converter != null)
|
273 |
// class attribute converter |
|
274 |
4 |
converter = contract.Converter;
|
275 |
251145 |
else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
|
276 |
// passed in converters |
|
277 |
83 |
converter = matchingConverter;
|
278 |
251062 |
else if (contract.InternalConverter != null)
|
279 |
// internally specified converter |
|
280 |
20 |
converter = contract.InternalConverter;
|
281 |
} |
|
282 |
251175 |
return converter;
|
283 |
251175 |
}
|
284 |
||
285 |
private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue) |
|
286 |
{ |
|
287 |
50289 |
CheckedRead(reader);
|
288 |
||
289 |
50289 |
string id = null;
|
290 |
||
291 |
50289 |
if (reader.TokenType == JsonToken.PropertyName)
|
292 |
{ |
|
293 |
bool specialProperty; |
|
294 |
||
295 |
do |
|
296 |
{ |
|
297 |
50328 |
string propertyName = reader.Value.ToString();
|
298 |
||
299 |
50328 |
if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
|
300 |
{ |
|
301 |
13 |
CheckedRead(reader);
|
302 |
13 |
if (reader.TokenType != JsonToken.String)
|
303 |
1 |
throw new JsonSerializationException("JSON reference {0} property must have a string value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
|
304 |
||
305 |
12 |
string reference = reader.Value.ToString();
|
306 |
||
307 |
12 |
CheckedRead(reader);
|
308 |
12 |
if (reader.TokenType == JsonToken.PropertyName)
|
309 |
1 |
throw new JsonSerializationException("Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
|
310 |
||
311 |
11 |
return Serializer.ReferenceResolver.ResolveReference(reference);
|
312 |
} |
|
313 |
50315 |
else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
|
314 |
{ |
|
315 |
14 |
CheckedRead(reader);
|
316 |
14 |
string qualifiedTypeName = reader.Value.ToString();
|
317 |
||
318 |
14 |
CheckedRead(reader);
|
319 |
||
320 |
14 |
if ((((member != null) ? member.TypeNameHandling : null) ?? Serializer.TypeNameHandling) != TypeNameHandling.None)
|
321 |
{ |
|
322 |
string typeName; |
|
323 |
string assemblyName; |
|
324 |
13 |
ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);
|
325 |
||
326 |
Type specifiedType; |
|
327 |
try |
|
328 |
{ |
|
329 |
13 |
specifiedType = Serializer.Binder.BindToType(assemblyName, typeName);
|
330 |
} |
|
331 |
0 |
catch (Exception ex)
|
332 |
{ |
|
333 |
0 |
throw new JsonSerializationException("Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
|
334 |
} |
|
335 |
||
336 |
13 |
if (specifiedType == null)
|
337 |
1 |
throw new JsonSerializationException("Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
|
338 |
||
339 |
12 |
if (objectType != null && !objectType.IsAssignableFrom(specifiedType))
|
340 |
1 |
throw new JsonSerializationException("Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
|
341 |
||
342 |
11 |
objectType = specifiedType;
|
343 |
11 |
contract = GetContractSafe(specifiedType);
|
344 |
} |
|
345 |
12 |
specialProperty = true;
|
346 |
} |
|
347 |
50301 |
else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
|
348 |
{ |
|
349 |
34 |
CheckedRead(reader);
|
350 |
||
351 |
33 |
id = reader.Value.ToString();
|
352 |
33 |
CheckedRead(reader);
|
353 |
33 |
specialProperty = true;
|
354 |
} |
|
355 |
50267 |
else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
|
356 |
{ |
|
357 |
6 |
CheckedRead(reader);
|
358 |
6 |
object list = CreateList(reader, objectType, contract, member, existingValue, id);
|
359 |
5 |
CheckedRead(reader);
|
360 |
5 |
return list;
|
361 |
} |
|
362 |
else |
|
363 |
{ |
|
364 |
50261 |
specialProperty = false;
|
365 |
} |
|
366 |
50306 |
} while (specialProperty
|
367 |
50306 |
&& reader.TokenType == JsonToken.PropertyName);
|
368 |
} |
|
369 |
||
370 |
50267 |
if (!HasDefinedType(objectType))
|
371 |
9 |
return CreateJObject(reader);
|
372 |
||
373 |
50258 |
if (contract == null)
|
374 |
0 |
throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
375 |
||
376 |
50258 |
JsonDictionaryContract dictionaryContract = contract as JsonDictionaryContract;
|
377 |
50258 |
if (dictionaryContract != null)
|
378 |
{ |
|
379 |
10021 |
if (existingValue == null)
|
380 |
10019 |
return CreateAndPopulateDictionary(reader, dictionaryContract, id);
|
381 |
||
382 |
2 |
return PopulateDictionary(dictionaryContract.CreateWrapper(existingValue), reader, dictionaryContract, id);
|
383 |
} |
|
384 |
||
385 |
40237 |
JsonObjectContract objectContract = contract as JsonObjectContract;
|
386 |
40237 |
if (objectContract != null)
|
387 |
{ |
|
388 |
40235 |
if (existingValue == null)
|
389 |
40233 |
return CreateAndPopulateObject(reader, objectContract, id);
|
390 |
||
391 |
2 |
return PopulateObject(existingValue, reader, objectContract, id);
|
392 |
} |
|
393 |
||
394 |
#if !SILVERLIGHT && !PocketPC |
|
395 |
2 |
JsonISerializableContract serializableContract = contract as JsonISerializableContract;
|
396 |
2 |
if (serializableContract != null)
|
397 |
{ |
|
398 |
1 |
return CreateISerializable(reader, serializableContract, id);
|
399 |
} |
|
400 |
#endif |
|
401 |
|
|
402 |
1 |
throw new JsonSerializationException("Cannot deserialize JSON object into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
403 |
50263 |
}
|
404 |
||
405 |
private JsonArrayContract EnsureArrayContract(Type objectType, JsonContract contract) |
|
406 |
{ |
|
407 |
20090 |
if (contract == null)
|
408 |
0 |
throw new JsonSerializationException("Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
409 |
||
410 |
20090 |
JsonArrayContract arrayContract = contract as JsonArrayContract;
|
411 |
20090 |
if (arrayContract == null)
|
412 |
1 |
throw new JsonSerializationException("Cannot deserialize JSON array into type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
413 |
||
414 |
20089 |
return arrayContract;
|
415 |
20089 |
}
|
416 |
||
417 |
private void CheckedRead(JsonReader reader) |
|
418 |
{ |
|
419 |
80483 |
if (!reader.Read())
|
420 |
1 |
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
421 |
80482 |
}
|
422 |
||
423 |
private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string reference) |
|
424 |
{ |
|
425 |
object value; |
|
426 |
20096 |
if (HasDefinedType(objectType))
|
427 |
{ |
|
428 |
20090 |
JsonArrayContract arrayContract = EnsureArrayContract(objectType, contract);
|
429 |
||
430 |
20089 |
if (existingValue == null)
|
431 |
20079 |
value = CreateAndPopulateList(reader, reference, arrayContract);
|
432 |
else |
|
433 |
10 |
value = PopulateList(arrayContract.CreateWrapper(existingValue), reader, reference, arrayContract);
|
434 |
} |
|
435 |
else |
|
436 |
{ |
|
437 |
6 |
value = CreateJToken(reader, contract);
|
438 |
} |
|
439 |
20091 |
return value;
|
440 |
20091 |
}
|
441 |
||
442 |
private bool HasDefinedType(Type type) |
|
443 |
{ |
|
444 |
70363 |
return (type != null && type != typeof (object) && !type.IsSubclassOf(typeof(JToken)));
|
445 |
70363 |
}
|
446 |
||
447 |
private object EnsureType(object value, Type targetType) |
|
448 |
{ |
|
449 |
210724 |
if (targetType == null)
|
450 |
11 |
return value;
|
451 |
||
452 |
210713 |
Type valueType = ReflectionUtils.GetObjectType(value);
|
453 |
||
454 |
// type of value and type of target don't match |
|
455 |
// attempt to convert value's type to target's type |
|
456 |
210713 |
if (valueType != targetType)
|
457 |
{ |
|
458 |
try |
|
459 |
{ |
|
460 |
60306 |
return ConvertUtils.ConvertOrCast(value, CultureInfo.InvariantCulture, targetType);
|
461 |
} |
|
462 |
4 |
catch (Exception ex)
|
463 |
{ |
|
464 |
4 |
throw new JsonSerializationException("Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, FormatValueForPrint(value), targetType), ex);
|
465 |
} |
|
466 |
} |
|
467 |
||
468 |
150407 |
return value;
|
469 |
210720 |
}
|
470 |
||
471 |
private string FormatValueForPrint(object value) |
|
472 |
{ |
|
473 |
4 |
if (value == null)
|
474 |
1 |
return "{null}";
|
475 |
||
476 |
3 |
if (value is string)
|
477 |
3 |
return @"""" + value + @"""";
|
478 |
||
479 |
0 |
return value.ToString();
|
480 |
4 |
}
|
481 |
||
482 |
private void SetPropertyValue(JsonProperty property, JsonReader reader, object target) |
|
483 |
{ |
|
484 |
160619 |
if (property.Ignored)
|
485 |
{ |
|
486 |
4 |
reader.Skip();
|
487 |
4 |
return;
|
488 |
} |
|
489 |
||
490 |
160615 |
object currentValue = null;
|
491 |
160615 |
bool useExistingValue = false;
|
492 |
160615 |
bool gottenCurrentValue = false;
|
493 |
||
494 |
160615 |
ObjectCreationHandling objectCreationHandling =
|
495 |
160615 |
property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
|
496 |
||
497 |
160615 |
if ((objectCreationHandling == ObjectCreationHandling.Auto || objectCreationHandling == ObjectCreationHandling.Reuse)
|
498 |
160615 |
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
|
499 |
160615 |
&& property.Readable)
|
500 |
{ |
|
501 |
103 |
currentValue = property.ValueProvider.GetValue(target);
|
502 |
103 |
gottenCurrentValue = true;
|
503 |
||
504 |
103 |
useExistingValue = (currentValue != null && !property.PropertyType.IsArray && !ReflectionUtils.InheritsGenericDefinition(property.PropertyType, typeof(ReadOnlyCollection<>)));
|
505 |
} |
|
506 |
||
507 |
160615 |
if (!property.Writable && !useExistingValue)
|
508 |
{ |
|
509 |
6 |
reader.Skip();
|
510 |
6 |
return;
|
511 |
} |
|
512 |
||
513 |
160609 |
object existingValue = (useExistingValue) ? currentValue : null;
|
514 |
160609 |
object value = CreateValueProperty(reader, property, target, gottenCurrentValue, existingValue);
|
515 |
||
516 |
// always set the value if useExistingValue is false, |
|
517 |
// otherwise also set it if CreateValue returns a new value compared to the currentValue |
|
518 |
// this could happen because of a JsonConverter against the type |
|
519 |
160604 |
if ((!useExistingValue || value != currentValue)
|
520 |
160604 |
&& ShouldSetPropertyValue(property, value))
|
521 |
160589 |
property.ValueProvider.SetValue(target, value);
|
522 |
160611 |
}
|
523 |
||
524 |
private bool ShouldSetPropertyValue(JsonProperty property, object value) |
|
525 |
{ |
|
526 |
160596 |
if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && value == null)
|
527 |
1 |
return false;
|
528 |
||
529 |
160595 |
if (property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling) == DefaultValueHandling.Ignore && Equals(value, property.DefaultValue))
|
530 |
0 |
return false;
|
531 |
||
532 |
160595 |
if (!property.Writable)
|
533 |
0 |
return false;
|
534 |
||
535 |
160595 |
return true;
|
536 |
160596 |
}
|
537 |
||
538 |
private object CreateAndPopulateDictionary(JsonReader reader, JsonDictionaryContract contract, string id) |
|
539 |
{ |
|
540 |
object dictionary; |
|
541 |
||
542 |
10019 |
if (contract.DefaultCreator != null &&
|
543 |
10019 |
(!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
|
544 |
10018 |
dictionary = contract.DefaultCreator();
|
545 |
else |
|
546 |
1 |
throw new JsonSerializationException("Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
547 |
||
548 |
10018 |
IWrappedDictionary dictionaryWrapper = contract.CreateWrapper(dictionary);
|
549 |
||
550 |
10018 |
PopulateDictionary(dictionaryWrapper, reader, contract, id);
|
551 |
||
552 |
10015 |
return dictionaryWrapper.UnderlyingDictionary;
|
553 |
10015 |
}
|
554 |
||
555 |
private object PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, string id) |
|
556 |
{ |
|
557 |
10021 |
if (id != null)
|
558 |
2 |
Serializer.ReferenceResolver.AddReference(id, dictionary.UnderlyingDictionary);
|
559 |
||
560 |
10021 |
contract.InvokeOnDeserializing(dictionary.UnderlyingDictionary, Serializer.Context);
|
561 |
||
562 |
10021 |
int initialDepth = reader.Depth;
|
563 |
||
564 |
do |
|
565 |
{ |
|
566 |
40064 |
switch (reader.TokenType)
|
567 |
{ |
|
568 |
case JsonToken.PropertyName: |
|
569 |
object keyValue; |
|
570 |
try |
|
571 |
{ |
|
572 |
30046 |
keyValue = EnsureType(reader.Value, contract.DictionaryKeyType);
|
573 |
} |
|
574 |
1 |
catch (Exception ex)
|
575 |
{ |
|
576 |
1 |
throw new JsonSerializationException("Could not convert string '{0}' to dictionary key type '{1}'. Create a TypeConverter to convert from the string to the key type object.".FormatWith(CultureInfo.InvariantCulture, reader.Value, contract.DictionaryKeyType), ex);
|
577 |
} |
|
578 |
||
579 |
30045 |
CheckedRead(reader);
|
580 |
||
581 |
try |
|
582 |
{ |
|
583 |
30045 |
dictionary[keyValue] = CreateValueNonProperty(reader, contract.DictionaryValueType, GetContractSafe(contract.DictionaryValueType));
|
584 |
} |
|
585 |
2 |
catch (Exception ex)
|
586 |
{ |
|
587 |
2 |
if (IsErrorHandled(dictionary, contract, keyValue, ex))
|
588 |
0 |
HandleError(reader, initialDepth);
|
589 |
else |
|
590 |
2 |
throw;
|
591 |
} |
|
592 |
30043 |
break;
|
593 |
case JsonToken.EndObject: |
|
594 |
10018 |
contract.InvokeOnDeserialized(dictionary.UnderlyingDictionary, Serializer.Context);
|
595 |
|
|
596 |
10018 |
return dictionary.UnderlyingDictionary;
|
597 |
default: |
|
598 |
0 |
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
599 |
} |
|
600 |
30043 |
} while (reader.Read());
|
601 |
||
602 |
0 |
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
603 |
10018 |
}
|
604 |
||
605 |
private object CreateAndPopulateList(JsonReader reader, string reference, JsonArrayContract contract) |
|
606 |
{ |
|
607 |
20079 |
return CollectionUtils.CreateAndPopulateList(contract.CreatedType, (l, isTemporaryListReference) =>
|
608 |
20079 |
{
|
609 |
20079 |
if (reference != null && isTemporaryListReference)
|
610 |
1 |
throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
611 |
20079 |
|
612 |
20079 |
#if !PocketPC
|
613 |
20078 |
if (contract.OnSerializing != null && isTemporaryListReference)
|
614 |
0 |
throw new JsonSerializationException("Cannot call OnSerializing on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
615 |
20079 |
#endif
|
616 |
20078 |
if (contract.OnError != null && isTemporaryListReference)
|
617 |
0 |
throw new JsonSerializationException("Cannot call OnError on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
618 |
20079 |
|
619 |
20078 |
PopulateList(contract.CreateWrapper(l), reader, reference, contract);
|
620 |
20079 |
});
|
621 |
20075 |
}
|
622 |
||
623 |
private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, string reference, JsonArrayContract contract) |
|
624 |
{ |
|
625 |
20089 |
object list = wrappedList.UnderlyingCollection;
|
626 |
||
627 |
20089 |
if (reference != null)
|
628 |
4 |
Serializer.ReferenceResolver.AddReference(reference, list);
|
629 |
||
630 |
20089 |
contract.InvokeOnDeserializing(list, Serializer.Context);
|
631 |
||
632 |
20089 |
int initialDepth = reader.Depth;
|
633 |
||
634 |
70341 |
while (reader.Read())
|
635 |
{ |
|
636 |
70340 |
switch (reader.TokenType)
|
637 |
{ |
|
638 |
case JsonToken.EndArray: |
|
639 |
20086 |
contract.InvokeOnDeserialized(list, Serializer.Context);
|
640 |
||
641 |
20086 |
return wrappedList.UnderlyingCollection;
|
642 |
case JsonToken.Comment: |
|
643 |
5 |
break;
|
644 |
default: |
|
645 |
try |
|
646 |
{ |
|
647 |
50249 |
object value = CreateValueNonProperty(reader, contract.CollectionItemType, GetContractSafe(contract.CollectionItemType));
|
648 |
||
649 |
50237 |
wrappedList.Add(value);
|
650 |
} |
|
651 |
13 |
catch (Exception ex)
|
652 |
{ |
|
653 |
13 |
if (IsErrorHandled(list, contract, wrappedList.Count, ex))
|
654 |
11 |
HandleError(reader, initialDepth);
|
655 |
else |
|
656 |
2 |
throw;
|
657 |
} |
|
658 |
50247 |
break;
|
659 |
} |
|
660 |
} |
|
661 |
||
662 |
0 |
throw new JsonSerializationException("Unexpected end when deserializing array.");
|
663 |
20086 |
}
|
664 |
||
665 |
#if !SILVERLIGHT && !PocketPC |
|
666 |
private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, string id) |
|
667 |
{ |
|
668 |
1 |
Type objectType = contract.UnderlyingType;
|
669 |
||
670 |
1 |
SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, GetFormatterConverter());
|
671 |
||
672 |
1 |
bool exit = false;
|
673 |
do |
|
674 |
{ |
|
675 |
19 |
switch (reader.TokenType)
|
676 |
{ |
|
677 |
case JsonToken.PropertyName: |
|
678 |
18 |
string memberName = reader.Value.ToString();
|
679 |
18 |
if (!reader.Read())
|
680 |
0 |
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
681 |
||
682 |
18 |
serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
|
683 |
18 |
break;
|
684 |
case JsonToken.EndObject: |
|
685 |
1 |
exit = true;
|
686 |
1 |
break;
|
687 |
default: |
|
688 |
0 |
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
689 |
} |
|
690 |
19 |
} while (!exit && reader.Read());
|
691 |
||
692 |
1 |
if (contract.ISerializableCreator == null)
|
693 |
0 |
throw new JsonSerializationException("ISerializable type '{0}' does not have a valid constructor.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
694 |
||
695 |
1 |
object createdObject = contract.ISerializableCreator(serializationInfo, Serializer.Context);
|
696 |
||
697 |
1 |
if (id != null)
|
698 |
0 |
Serializer.ReferenceResolver.AddReference(id, createdObject);
|
699 |
||
700 |
1 |
contract.InvokeOnDeserializing(createdObject, Serializer.Context);
|
701 |
1 |
contract.InvokeOnDeserialized(createdObject, Serializer.Context);
|
702 |
||
703 |
1 |
return createdObject;
|
704 |
1 |
}
|
705 |
#endif |
|
706 |
||
707 |
private object CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, string id) |
|
708 |
{ |
|
709 |
40233 |
object newObject = null;
|
710 |
||
711 |
40233 |
if (contract.UnderlyingType.IsInterface || contract.UnderlyingType.IsAbstract)
|
712 |
1 |
throw new JsonSerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
|
713 |
||
714 |
40232 |
if (contract.DefaultCreator != null &&
|
715 |
40232 |
(!contract.DefaultCreatorNonPublic || Serializer.ConstructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
|
716 |
{ |
|
717 |
40217 |
newObject = contract.DefaultCreator();
|
718 |
} |
|
719 |
||
720 |
40232 |
if (newObject != null)
|
721 |
{ |
|
722 |
40217 |
PopulateObject(newObject, reader, contract, id);
|
723 |
40206 |
return newObject;
|
724 |
} |
|
725 |
||
726 |
15 |
return CreateObjectFromNonDefaultConstructor(reader, contract, id);
|
727 |
40218 |
}
|
728 |
||
729 |
private object CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, string id) |
|
730 |
{ |
|
731 |
15 |
Type objectType = contract.UnderlyingType;
|
732 |
||
733 |
15 |
if (contract.ParametrizedConstructor == null)
|
734 |
2 |
throw new JsonSerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor or only one constructor with arguments.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
735 |
||
736 |
// create a dictionary to put retrieved values into |
|
737 |
13 |
IDictionary<JsonProperty, object> propertyValues = contract.Properties.Where(p => !p.Ignored).ToDictionary(kv => kv, kv => (object)null);
|
738 |
||
739 |
13 |
bool exit = false;
|
740 |
do |
|
741 |
{ |
|
742 |
42 |
switch (reader.TokenType)
|
743 |
{ |
|
744 |
case JsonToken.PropertyName: |
|
745 |
29 |
string memberName = reader.Value.ToString();
|
746 |
29 |
if (!reader.Read())
|
747 |
0 |
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
748 |
||
749 |
// attempt exact case match first |
|
750 |
// then try match ignoring case |
|
751 |
29 |
JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
|
752 |
||
753 |
29 |
if (property != null)
|
754 |
{ |
|
755 |
28 |
if (!property.Ignored)
|
756 |
27 |
propertyValues[property] = CreateValueProperty(reader, property, null, true, null);
|
757 |
else |
|
758 |
1 |
reader.Skip();
|
759 |
} |
|
760 |
else |
|
761 |
{ |
|
762 |
1 |
if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
|
763 |
0 |
throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
|
764 |
||
765 |
1 |
reader.Skip();
|
766 |
} |
|
767 |
29 |
break;
|
768 |
case JsonToken.EndObject: |
|
769 |
13 |
exit = true;
|
770 |
13 |
break;
|
771 |
default: |
|
772 |
0 |
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
773 |
} |
|
774 |
42 |
} while (!exit && reader.Read());
|
775 |
||
776 |
13 |
IDictionary<ParameterInfo, object> constructorParameters = contract.ParametrizedConstructor.GetParameters().ToDictionary(p => p, p => (object)null);
|
777 |
13 |
IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
|
778 |
||
779 |
13 |
foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
|
780 |
{ |
|
781 |
28 |
ParameterInfo matchingConstructorParameter = constructorParameters.ForgivingCaseSensitiveFind(kv => kv.Key.Name, propertyValue.Key.PropertyName).Key;
|
782 |
28 |
if (matchingConstructorParameter != null)
|
783 |
20 |
constructorParameters[matchingConstructorParameter] = propertyValue.Value;
|
784 |
else |
|
785 |
8 |
remainingPropertyValues.Add(propertyValue);
|
786 |
} |
|
787 |
||
788 |
13 |
object createdObject = contract.ParametrizedConstructor.Invoke(constructorParameters.Values.ToArray());
|
789 |
||
790 |
12 |
if (id != null)
|
791 |
0 |
Serializer.ReferenceResolver.AddReference(id, createdObject);
|
792 |
||
793 |
12 |
contract.InvokeOnDeserializing(createdObject, Serializer.Context);
|
794 |
||
795 |
// go through unused values and set the newly created object's properties |
|
796 |
6 |
foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues)
|
797 |
{ |
|
798 |
6 |
JsonProperty property = remainingPropertyValue.Key;
|
799 |
6 |
object value = remainingPropertyValue.Value;
|
800 |
||
801 |
6 |
if (ShouldSetPropertyValue(remainingPropertyValue.Key, remainingPropertyValue.Value))
|
802 |
6 |
property.ValueProvider.SetValue(createdObject, value);
|
803 |
} |
|
804 |
||
805 |
12 |
contract.InvokeOnDeserialized(createdObject, Serializer.Context);
|
806 |
12 |
return createdObject;
|
807 |
12 |
}
|
808 |
||
809 |
private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, string id) |
|
810 |
{ |
|
811 |
40229 |
contract.InvokeOnDeserializing(newObject, Serializer.Context);
|
812 |
||
813 |
40229 |
Dictionary<JsonProperty, RequiredValue> requiredProperties =
|
814 |
18 |
contract.Properties.Where(m => m.Required != Required.Default).ToDictionary(m => m, m => RequiredValue.None); |
815 |
||
816 |
40229 |
if (id != null)
|
817 |
26 |
Serializer.ReferenceResolver.AddReference(id, newObject);
|
818 |
||
819 |
40229 |
int initialDepth = reader.Depth;
|
820 |
||
821 |
do |
|
822 |
{ |
|
823 |
200881 |
switch (reader.TokenType)
|
824 |
{ |
|
825 |
case JsonToken.PropertyName: |
|
826 |
160657 |
string memberName = reader.Value.ToString();
|
827 |
||
828 |
// attempt exact case match first |
|
829 |
// then try match ignoring case |
|
830 |
160657 |
JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
|
831 |
||
832 |
160657 |
if (property == null)
|
833 |
{ |
|
834 |
38 |
if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
|
835 |
2 |
throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
|
836 |
||
837 |
36 |
reader.Skip();
|
838 |
36 |
continue;
|
839 |
} |
|
840 |
||
841 |
160619 |
if (property.PropertyType == typeof(byte[]))
|
842 |
{ |
|
843 |
6 |
reader.ReadAsBytes();
|
844 |
} |
|
845 |
else |
|
846 |
{ |
|
847 |
160613 |
if (!reader.Read())
|
848 |
0 |
throw new JsonSerializationException(
|
849 |
0 |
"Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
850 |
} |
|
851 |
||
852 |
160619 |
SetRequiredProperty(reader, property, requiredProperties);
|
853 |
||
854 |
try |
|
855 |
{ |
|
856 |
160619 |
SetPropertyValue(property, reader, newObject);
|
857 |
} |
|
858 |
8 |
catch (Exception ex)
|
859 |
{ |
|
860 |
8 |
if (IsErrorHandled(newObject, contract, memberName, ex))
|
861 |
1 |
HandleError(reader, initialDepth);
|
862 |
else |
|
863 |
7 |
throw;
|
864 |
} |
|
865 |
160612 |
break;
|
866 |
case JsonToken.EndObject: |
|
867 |
40220 |
foreach (KeyValuePair<JsonProperty, RequiredValue> requiredProperty in requiredProperties)
|
868 |
{ |
|
869 |
160606 |
if (requiredProperty.Value == RequiredValue.None)
|
870 |
1 |
throw new JsonSerializationException("Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName));
|
871 |
160605 |
if (requiredProperty.Key.Required == Required.Always && requiredProperty.Value == RequiredValue.Null)
|
872 |
1 |
throw new JsonSerializationException("Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, requiredProperty.Key.PropertyName));
|
873 |
} |
|
874 |
||
875 |
40218 |
contract.InvokeOnDeserialized(newObject, Serializer.Context);
|
876 |
40218 |
return newObject;
|
877 |
case JsonToken.Comment: |
|
878 |
// ignore |
|
879 |
4 |
break;
|
880 |
default: |
|
881 |
0 |
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
882 |
} |
|
883 |
160652 |
} while (reader.Read());
|
884 |
||
885 |
0 |
throw new JsonSerializationException("Unexpected end when deserializing object.");
|
886 |
40218 |
}
|
887 |
||
888 |
private void SetRequiredProperty(JsonReader reader, JsonProperty property, Dictionary<JsonProperty, RequiredValue> requiredProperties) |
|
889 |
{ |
|
890 |
160619 |
if (property != null)
|
891 |
{ |
|
892 |
160619 |
requiredProperties[property] = (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.Undefined)
|
893 |
160619 |
? RequiredValue.Null
|
894 |
160619 |
: RequiredValue.Value;
|
895 |
} |
|
896 |
160619 |
}
|
897 |
||
898 |
private void HandleError(JsonReader reader, int initialDepth) |
|
899 |
{ |
|
900 |
12 |
ClearErrorContext();
|
901 |
||
902 |
12 |
reader.Skip();
|
903 |
||
904 |
21 |
while (reader.Depth > (initialDepth + 1))
|
905 |
{ |
|
906 |
9 |
reader.Read();
|
907 |
} |
|
908 |
12 |
}
|
909 |
||
910 |
internal enum RequiredValue |
|
911 |
{ |
|
912 |
None, |
|
913 |
Null, |
|
914 |
Value |
|
915 |
} |
|
916 |
} |
|
917 |
} |