Code Coverage Statistics for Source File
Newtonsoft.Json\Linq\JObject.cs
Symbol Coverage: 95.51% (149 of 156)
Branch Coverage: 85.19% (92 of 108)
Cyclomatic Complexity Avg: 1.76 Max:7
Code Lines: 149
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.Generic; |
|
28 |
using System.Collections.Specialized; |
|
29 |
using System.ComponentModel; |
|
30 |
using System.Linq; |
|
31 |
using System.IO; |
|
32 |
using Newtonsoft.Json.Utilities; |
|
33 |
using System.Globalization; |
|
34 |
#if !PocketPC && !SILVERLIGHT |
|
35 |
using Newtonsoft.Json.Linq.ComponentModel; |
|
36 |
#endif |
|
37 |
||
38 |
namespace Newtonsoft.Json.Linq |
|
39 |
{ |
|
40 |
/// <summary> |
|
41 |
/// Represents a JSON object. |
|
42 |
/// </summary> |
|
43 |
#if !PocketPC && !SILVERLIGHT |
|
44 |
[TypeDescriptionProvider(typeof(JTypeDescriptionProvider))] |
|
45 |
#endif |
|
46 |
public class JObject : JContainer, IDictionary<string, JToken>, INotifyPropertyChanged |
|
47 |
#if !PocketPC && !SILVERLIGHT && !NET20 |
|
48 |
, INotifyPropertyChanging |
|
49 |
#endif |
|
50 |
{ |
|
51 |
/// <summary> |
|
52 |
/// Occurs when a property value changes. |
|
53 |
/// </summary> |
|
54 |
public event PropertyChangedEventHandler PropertyChanged; |
|
55 |
||
56 |
#if !PocketPC && !SILVERLIGHT && !NET20 |
|
57 |
/// <summary> |
|
58 |
/// Occurs when a property value is changing. |
|
59 |
/// </summary> |
|
60 |
public event PropertyChangingEventHandler PropertyChanging; |
|
61 |
#endif |
|
62 |
||
63 |
/// <summary> |
|
64 |
/// Initializes a new instance of the <see cref="JObject"/> class. |
|
65 |
/// </summary> |
|
66 |
210 |
public JObject()
|
67 |
{ |
|
68 |
210 |
}
|
69 |
||
70 |
/// <summary> |
|
71 |
/// Initializes a new instance of the <see cref="JObject"/> class from another <see cref="JObject"/> object. |
|
72 |
/// </summary> |
|
73 |
/// <param name="other">A <see cref="JObject"/> object to copy from.</param> |
|
74 |
1 |
public JObject(JObject other)
|
75 |
1 |
: base(other)
|
76 |
{ |
|
77 |
1 |
}
|
78 |
||
79 |
/// <summary> |
|
80 |
/// Initializes a new instance of the <see cref="JObject"/> class with the specified content. |
|
81 |
/// </summary> |
|
82 |
/// <param name="content">The contents of the object.</param> |
|
83 |
43 |
public JObject(params object[] content)
|
84 |
43 |
: this((object)content)
|
85 |
{ |
|
86 |
43 |
}
|
87 |
||
88 |
/// <summary> |
|
89 |
/// Initializes a new instance of the <see cref="JObject"/> class with the specified content. |
|
90 |
/// </summary> |
|
91 |
/// <param name="content">The contents of the object.</param> |
|
92 |
62 |
public JObject(object content)
|
93 |
{ |
|
94 |
62 |
Add(content);
|
95 |
62 |
}
|
96 |
||
97 |
internal override bool DeepEquals(JToken node) |
|
98 |
{ |
|
99 |
6 |
JObject t = node as JObject;
|
100 |
6 |
return (t != null && ContentsEqual(t));
|
101 |
6 |
}
|
102 |
||
103 |
internal override void ValidateToken(JToken o, JToken existing) |
|
104 |
{ |
|
105 |
691 |
ValidationUtils.ArgumentNotNull(o, "o");
|
106 |
||
107 |
691 |
if (o.Type != JTokenType.Property)
|
108 |
5 |
throw new ArgumentException("Can not add {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, o.GetType(), GetType()));
|
109 |
||
110 |
// looping over all properties every time isn't good |
|
111 |
// need to think about performance here |
|
112 |
686 |
JProperty property = (JProperty)o;
|
113 |
686 |
foreach (JProperty childProperty in Children())
|
114 |
{ |
|
115 |
1158 |
if (childProperty != existing && string.Equals(childProperty.Name, property.Name, StringComparison.Ordinal))
|
116 |
5 |
throw new ArgumentException("Can not add property {0} to {1}. Property with the same name already exists on object.".FormatWith(CultureInfo.InvariantCulture, property.Name, GetType()));
|
117 |
} |
|
118 |
681 |
}
|
119 |
||
120 |
internal void InternalPropertyChanged(JProperty childProperty) |
|
121 |
{ |
|
122 |
8 |
OnPropertyChanged(childProperty.Name);
|
123 |
#if !SILVERLIGHT |
|
124 |
8 |
OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, IndexOfItem(childProperty)));
|
125 |
#else |
|
126 |
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, childProperty, childProperty, IndexOfItem(childProperty))); |
|
127 |
#endif |
|
128 |
8 |
}
|
129 |
||
130 |
internal void InternalPropertyChanging(JProperty childProperty) |
|
131 |
{ |
|
132 |
#if !PocketPC && !SILVERLIGHT && !NET20 |
|
133 |
8 |
OnPropertyChanging(childProperty.Name);
|
134 |
#endif |
|
135 |
8 |
}
|
136 |
||
137 |
internal override JToken CloneToken() |
|
138 |
{ |
|
139 |
1 |
return new JObject(this);
|
140 |
1 |
}
|
141 |
||
142 |
/// <summary> |
|
143 |
/// Gets the node type for this <see cref="JToken"/>. |
|
144 |
/// </summary> |
|
145 |
/// <value>The type.</value> |
|
146 |
public override JTokenType Type |
|
147 |
{ |
|
148 |
139 |
get { return JTokenType.Object; }
|
149 |
} |
|
150 |
||
151 |
/// <summary> |
|
152 |
/// Gets an <see cref="IEnumerable{JProperty}"/> of this object's properties. |
|
153 |
/// </summary> |
|
154 |
/// <returns>An <see cref="IEnumerable{JProperty}"/> of this object's properties.</returns> |
|
155 |
public IEnumerable<JProperty> Properties() |
|
156 |
{ |
|
157 |
692 |
return Children().Cast<JProperty>();
|
158 |
692 |
}
|
159 |
||
160 |
/// <summary> |
|
161 |
/// Gets a <see cref="JProperty"/> the specified name. |
|
162 |
/// </summary> |
|
163 |
/// <param name="name">The property name.</param> |
|
164 |
/// <returns>A <see cref="JProperty"/> with the specified name or null.</returns> |
|
165 |
public JProperty Property(string name) |
|
166 |
{ |
|
167 |
614 |
return Properties()
|
168 |
614 |
.Where(p => string.Equals(p.Name, name, StringComparison.Ordinal))
|
169 |
614 |
.SingleOrDefault();
|
170 |
614 |
}
|
171 |
||
172 |
/// <summary> |
|
173 |
/// Gets an <see cref="JEnumerable{JToken}"/> of this object's property values. |
|
174 |
/// </summary> |
|
175 |
/// <returns>An <see cref="JEnumerable{JToken}"/> of this object's property values.</returns> |
|
176 |
public JEnumerable<JToken> PropertyValues() |
|
177 |
{ |
|
178 |
1 |
return new JEnumerable<JToken>(Properties().Select(p => p.Value));
|
179 |
1 |
}
|
180 |
||
181 |
/// <summary> |
|
182 |
/// Gets the <see cref="JToken"/> with the specified key. |
|
183 |
/// </summary> |
|
184 |
/// <value>The <see cref="JToken"/> with the specified key.</value> |
|
185 |
public override JToken this[object key] |
|
186 |
{ |
|
187 |
get |
|
188 |
{ |
|
189 |
66 |
ValidationUtils.ArgumentNotNull(key, "o");
|
190 |
||
191 |
66 |
string propertyName = key as string;
|
192 |
66 |
if (propertyName == null)
|
193 |
1 |
throw new ArgumentException("Accessed JObject values with invalid key value: {0}. Object property name expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
194 |
||
195 |
65 |
return this[propertyName];
|
196 |
65 |
}
|
197 |
set |
|
198 |
{ |
|
199 |
2 |
ValidationUtils.ArgumentNotNull(key, "o");
|
200 |
||
201 |
2 |
string propertyName = key as string;
|
202 |
2 |
if (propertyName == null)
|
203 |
1 |
throw new ArgumentException("Set JObject values with invalid key value: {0}. Object property name expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
|
204 |
||
205 |
1 |
this[propertyName] = value;
|
206 |
1 |
}
|
207 |
} |
|
208 |
||
209 |
/// <summary> |
|
210 |
/// Gets or sets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name. |
|
211 |
/// </summary> |
|
212 |
/// <value></value> |
|
213 |
public JToken this[string propertyName] |
|
214 |
{ |
|
215 |
get |
|
216 |
{ |
|
217 |
187 |
ValidationUtils.ArgumentNotNull(propertyName, "propertyName");
|
218 |
||
219 |
187 |
JProperty property = Property(propertyName);
|
220 |
||
221 |
187 |
return (property != null) ? property.Value : null;
|
222 |
187 |
}
|
223 |
set |
|
224 |
{ |
|
225 |
50 |
JProperty property = Property(propertyName);
|
226 |
50 |
if (property != null)
|
227 |
{ |
|
228 |
12 |
property.Value = value;
|
229 |
} |
|
230 |
else |
|
231 |
{ |
|
232 |
#if !PocketPC && !SILVERLIGHT && !NET20 |
|
233 |
38 |
OnPropertyChanging(propertyName);
|
234 |
#endif |
|
235 |
38 |
Add(new JProperty(propertyName, value));
|
236 |
38 |
OnPropertyChanged(propertyName);
|
237 |
} |
|
238 |
50 |
}
|
239 |
} |
|
240 |
||
241 |
/// <summary> |
|
242 |
/// Loads an <see cref="JObject"/> from a <see cref="JsonReader"/>. |
|
243 |
/// </summary> |
|
244 |
/// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JObject"/>.</param> |
|
245 |
/// <returns>A <see cref="JObject"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns> |
|
246 |
public static JObject Load(JsonReader reader) |
|
247 |
{ |
|
248 |
57 |
ValidationUtils.ArgumentNotNull(reader, "reader");
|
249 |
||
250 |
57 |
if (reader.TokenType == JsonToken.None)
|
251 |
{ |
|
252 |
29 |
if (!reader.Read())
|
253 |
0 |
throw new Exception("Error reading JObject from JsonReader.");
|
254 |
} |
|
255 |
57 |
if (reader.TokenType != JsonToken.StartObject)
|
256 |
1 |
throw new Exception(
|
257 |
1 |
"Error reading JObject from JsonReader. Current JsonReader item is not an object: {0}".FormatWith(
|
258 |
1 |
CultureInfo.InvariantCulture, reader.TokenType));
|
259 |
||
260 |
56 |
JObject o = new JObject();
|
261 |
56 |
o.SetLineInfo(reader as IJsonLineInfo);
|
262 |
|
|
263 |
56 |
if (!reader.Read())
|
264 |
0 |
throw new Exception("Error reading JObject from JsonReader.");
|
265 |
||
266 |
56 |
o.ReadContentFrom(reader);
|
267 |
||
268 |
55 |
return o;
|
269 |
55 |
}
|
270 |
||
271 |
/// <summary> |
|
272 |
/// Load a <see cref="JObject"/> from a string that contains JSON. |
|
273 |
/// </summary> |
|
274 |
/// <param name="json">A <see cref="String"/> that contains JSON.</param> |
|
275 |
/// <returns>A <see cref="JObject"/> populated from the string that contains JSON.</returns> |
|
276 |
public static JObject Parse(string json) |
|
277 |
{ |
|
278 |
29 |
JsonReader jsonReader = new JsonTextReader(new StringReader(json));
|
279 |
||
280 |
29 |
return Load(jsonReader);
|
281 |
27 |
}
|
282 |
||
283 |
/// <summary> |
|
284 |
/// Creates a <see cref="JObject"/> from an object. |
|
285 |
/// </summary> |
|
286 |
/// <param name="o">The object that will be used to create <see cref="JObject"/>.</param> |
|
287 |
/// <returns>A <see cref="JObject"/> with the values of the specified object</returns> |
|
288 |
public static new JObject FromObject(object o) |
|
289 |
{ |
|
290 |
5 |
return FromObject(o, new JsonSerializer());
|
291 |
5 |
}
|
292 |
||
293 |
/// <summary> |
|
294 |
/// Creates a <see cref="JArray"/> from an object. |
|
295 |
/// </summary> |
|
296 |
/// <param name="o">The object that will be used to create <see cref="JArray"/>.</param> |
|
297 |
/// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used to read the object.</param> |
|
298 |
/// <returns>A <see cref="JArray"/> with the values of the specified object</returns> |
|
299 |
public static new JObject FromObject(object o, JsonSerializer jsonSerializer) |
|
300 |
{ |
|
301 |
8 |
JToken token = FromObjectInternal(o, jsonSerializer);
|
302 |
||
303 |
8 |
if (token != null && token.Type != JTokenType.Object)
|
304 |
0 |
throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type));
|
305 |
||
306 |
8 |
return (JObject)token;
|
307 |
8 |
}
|
308 |
||
309 |
/// <summary> |
|
310 |
/// Writes this token to a <see cref="JsonWriter"/>. |
|
311 |
/// </summary> |
|
312 |
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param> |
|
313 |
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param> |
|
314 |
public override void WriteTo(JsonWriter writer, params JsonConverter[] converters) |
|
315 |
{ |
|
316 |
56 |
writer.WriteStartObject();
|
317 |
||
318 |
56 |
foreach (JProperty property in Properties())
|
319 |
{ |
|
320 |
174 |
property.WriteTo(writer, converters);
|
321 |
} |
|
322 |
||
323 |
56 |
writer.WriteEndObject();
|
324 |
56 |
}
|
325 |
||
326 |
#region IDictionary<string,JToken> Members |
|
327 |
/// <summary> |
|
328 |
/// Adds the specified property name. |
|
329 |
/// </summary> |
|
330 |
/// <param name="propertyName">Name of the property.</param> |
|
331 |
/// <param name="value">The value.</param> |
|
332 |
public void Add(string propertyName, JToken value) |
|
333 |
{ |
|
334 |
24 |
Add(new JProperty(propertyName, value));
|
335 |
23 |
}
|
336 |
||
337 |
bool IDictionary<string, JToken>.ContainsKey(string key) |
|
338 |
{ |
|
339 |
1 |
return (Property(key) != null);
|
340 |
1 |
}
|
341 |
||
342 |
ICollection<string> IDictionary<string, JToken>.Keys |
|
343 |
{ |
|
344 |
0 |
get { throw new NotImplementedException(); }
|
345 |
} |
|
346 |
||
347 |
/// <summary> |
|
348 |
/// Removes the property with the specified name. |
|
349 |
/// </summary> |
|
350 |
/// <param name="propertyName">Name of the property.</param> |
|
351 |
/// <returns>true if item was successfully removed; otherwise, false.</returns> |
|
352 |
public bool Remove(string propertyName) |
|
353 |
{ |
|
354 |
4 |
JProperty property = Property(propertyName);
|
355 |
4 |
if (property == null)
|
356 |
2 |
return false;
|
357 |
||
358 |
2 |
property.Remove();
|
359 |
2 |
return true;
|
360 |
4 |
}
|
361 |
||
362 |
/// <summary> |
|
363 |
/// Tries the get value. |
|
364 |
/// </summary> |
|
365 |
/// <param name="propertyName">Name of the property.</param> |
|
366 |
/// <param name="value">The value.</param> |
|
367 |
/// <returns>true if a value was successfully retrieved; otherwise, false.</returns> |
|
368 |
public bool TryGetValue(string propertyName, out JToken value) |
|
369 |
{ |
|
370 |
6 |
JProperty property = Property(propertyName);
|
371 |
6 |
if (property == null)
|
372 |
{ |
|
373 |
2 |
value = null;
|
374 |
2 |
return false;
|
375 |
} |
|
376 |
||
377 |
4 |
value = property.Value;
|
378 |
4 |
return true;
|
379 |
6 |
}
|
380 |
||
381 |
ICollection<JToken> IDictionary<string, JToken>.Values |
|
382 |
{ |
|
383 |
0 |
get { throw new NotImplementedException(); }
|
384 |
} |
|
385 |
||
386 |
#endregion |
|
387 |
||
388 |
#region ICollection<KeyValuePair<string,JToken>> Members |
|
389 |
||
390 |
void ICollection<KeyValuePair<string,JToken>>.Add(KeyValuePair<string, JToken> item) |
|
391 |
{ |
|
392 |
1 |
Add(new JProperty(item.Key, item.Value));
|
393 |
1 |
}
|
394 |
||
395 |
void ICollection<KeyValuePair<string, JToken>>.Clear() |
|
396 |
{ |
|
397 |
1 |
RemoveAll();
|
398 |
1 |
}
|
399 |
||
400 |
bool ICollection<KeyValuePair<string,JToken>>.Contains(KeyValuePair<string, JToken> item) |
|
401 |
{ |
|
402 |
9 |
JProperty property = Property(item.Key);
|
403 |
9 |
if (property == null)
|
404 |
3 |
return false;
|
405 |
||
406 |
6 |
return (property.Value == item.Value);
|
407 |
9 |
}
|
408 |
||
409 |
void ICollection<KeyValuePair<string,JToken>>.CopyTo(KeyValuePair<string, JToken>[] array, int arrayIndex) |
|
410 |
{ |
|
411 |
5 |
if (array == null)
|
412 |
1 |
throw new ArgumentNullException("array");
|
413 |
4 |
if (arrayIndex < 0)
|
414 |
1 |
throw new ArgumentOutOfRangeException("arrayIndex", "arrayIndex is less than 0.");
|
415 |
3 |
if (arrayIndex >= array.Length)
|
416 |
1 |
throw new ArgumentException("arrayIndex is equal to or greater than the length of array.");
|
417 |
2 |
if (Count > array.Length - arrayIndex)
|
418 |
1 |
throw new ArgumentException("The number of elements in the source JObject is greater than the available space from arrayIndex to the end of the destination array.");
|
419 |
||
420 |
1 |
int index = 0;
|
421 |
1 |
foreach (JProperty property in Properties())
|
422 |
{ |
|
423 |
3 |
array[arrayIndex + index] = new KeyValuePair<string, JToken>(property.Name, property.Value);
|
424 |
3 |
index++;
|
425 |
} |
|
426 |
1 |
}
|
427 |
||
428 |
/// <summary> |
|
429 |
/// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. |
|
430 |
/// </summary> |
|
431 |
/// <value></value> |
|
432 |
/// <returns>The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</returns> |
|
433 |
public int Count |
|
434 |
{ |
|
435 |
5 |
get { return Children().Count(); }
|
436 |
} |
|
437 |
||
438 |
bool ICollection<KeyValuePair<string,JToken>>.IsReadOnly |
|
439 |
{ |
|
440 |
0 |
get { return false; }
|
441 |
} |
|
442 |
||
443 |
bool ICollection<KeyValuePair<string,JToken>>.Remove(KeyValuePair<string, JToken> item) |
|
444 |
{ |
|
445 |
4 |
if (!((ICollection<KeyValuePair<string,JToken>>)this).Contains(item))
|
446 |
3 |
return false;
|
447 |
||
448 |
1 |
((IDictionary<string, JToken>)this).Remove(item.Key);
|
449 |
1 |
return true;
|
450 |
4 |
}
|
451 |
||
452 |
#endregion |
|
453 |
||
454 |
internal override int GetDeepHashCode() |
|
455 |
{ |
|
456 |
4 |
return ContentsHashCode();
|
457 |
4 |
}
|
458 |
||
459 |
/// <summary> |
|
460 |
/// Returns an enumerator that iterates through the collection. |
|
461 |
/// </summary> |
|
462 |
/// <returns> |
|
463 |
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. |
|
464 |
/// </returns> |
|
465 |
public IEnumerator<KeyValuePair<string, JToken>> GetEnumerator() |
|
466 |
{ |
|
467 |
12 |
foreach (JProperty property in Properties())
|
468 |
{ |
|
469 |
31 |
yield return new KeyValuePair<string, JToken>(property.Name, property.Value);
|
470 |
} |
|
471 |
} |
|
472 |
||
473 |
/// <summary> |
|
474 |
/// Raises the <see cref="PropertyChanged"/> event with the provided arguments. |
|
475 |
/// </summary> |
|
476 |
/// <param name="propertyName">Name of the property.</param> |
|
477 |
protected virtual void OnPropertyChanged(string propertyName) |
|
478 |
{ |
|
479 |
46 |
if (PropertyChanged != null)
|
480 |
8 |
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
481 |
46 |
}
|
482 |
||
483 |
#if !PocketPC && !SILVERLIGHT && !NET20 |
|
484 |
/// <summary> |
|
485 |
/// Raises the <see cref="PropertyChanging"/> event with the provided arguments. |
|
486 |
/// </summary> |
|
487 |
/// <param name="propertyName">Name of the property.</param> |
|
488 |
protected virtual void OnPropertyChanging(string propertyName) |
|
489 |
{ |
|
490 |
46 |
if (PropertyChanging != null)
|
491 |
4 |
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
|
492 |
46 |
}
|
493 |
#endif |
|
494 |
} |
|
495 |
} |