root / Assets / Plugins / LitJson / JsonMapper.cs @ 11:01dde4258840
History | View | Annotate | Download (29.6 kB)
1 | #region Header |
---|---|
2 | /** |
3 | * JsonMapper.cs |
4 | * JSON to .Net object and object to JSON conversions. |
5 | * |
6 | * The authors disclaim copyright to this source code. For more details, see |
7 | * the COPYING file included with this distribution. |
8 | **/ |
9 | #endregion |
10 | |
11 | |
12 | using System; |
13 | using System.Collections; |
14 | using System.Collections.Generic; |
15 | using System.Globalization; |
16 | using System.IO; |
17 | using System.Reflection; |
18 | |
19 | |
20 | namespace LitJson |
21 | { |
22 | internal struct PropertyMetadata |
23 | { |
24 | public MemberInfo Info; |
25 | public bool IsField; |
26 | public Type Type; |
27 | } |
28 | |
29 | |
30 | internal struct ArrayMetadata |
31 | { |
32 | private Type element_type; |
33 | private bool is_array; |
34 | private bool is_list; |
35 | |
36 | |
37 | public Type ElementType { |
38 | get { |
39 | if (element_type == null) |
40 | return typeof (JsonData); |
41 | |
42 | return element_type; |
43 | } |
44 | |
45 | set { element_type = value; } |
46 | } |
47 | |
48 | public bool IsArray { |
49 | get { return is_array; } |
50 | set { is_array = value; } |
51 | } |
52 | |
53 | public bool IsList { |
54 | get { return is_list; } |
55 | set { is_list = value; } |
56 | } |
57 | } |
58 | |
59 | |
60 | internal struct ObjectMetadata |
61 | { |
62 | private Type element_type; |
63 | private bool is_dictionary; |
64 | |
65 | private IDictionary<string, PropertyMetadata> properties; |
66 | |
67 | |
68 | public Type ElementType { |
69 | get { |
70 | if (element_type == null) |
71 | return typeof (JsonData); |
72 | |
73 | return element_type; |
74 | } |
75 | |
76 | set { element_type = value; } |
77 | } |
78 | |
79 | public bool IsDictionary { |
80 | get { return is_dictionary; } |
81 | set { is_dictionary = value; } |
82 | } |
83 | |
84 | public IDictionary<string, PropertyMetadata> Properties { |
85 | get { return properties; } |
86 | set { properties = value; } |
87 | } |
88 | } |
89 | |
90 | |
91 | internal delegate void ExporterFunc (object obj, JsonWriter writer); |
92 | public delegate void ExporterFunc<T> (T obj, JsonWriter writer); |
93 | |
94 | internal delegate object ImporterFunc (object input); |
95 | public delegate TValue ImporterFunc<TJson, TValue> (TJson input); |
96 | |
97 | public delegate IJsonWrapper WrapperFactory (); |
98 | |
99 | |
100 | public class JsonMapper |
101 | { |
102 | #region Fields |
103 | private static int max_nesting_depth; |
104 | |
105 | private static IFormatProvider datetime_format; |
106 | |
107 | private static IDictionary<Type, ExporterFunc> base_exporters_table; |
108 | private static IDictionary<Type, ExporterFunc> custom_exporters_table; |
109 | |
110 | private static IDictionary<Type, |
111 | IDictionary<Type, ImporterFunc>> base_importers_table; |
112 | private static IDictionary<Type, |
113 | IDictionary<Type, ImporterFunc>> custom_importers_table; |
114 | |
115 | private static IDictionary<Type, ArrayMetadata> array_metadata; |
116 | private static readonly object array_metadata_lock = new Object (); |
117 | |
118 | private static IDictionary<Type, |
119 | IDictionary<Type, MethodInfo>> conv_ops; |
120 | private static readonly object conv_ops_lock = new Object (); |
121 | |
122 | private static IDictionary<Type, ObjectMetadata> object_metadata; |
123 | private static readonly object object_metadata_lock = new Object (); |
124 | |
125 | private static IDictionary<Type, |
126 | IList<PropertyMetadata>> type_properties; |
127 | private static readonly object type_properties_lock = new Object (); |
128 | |
129 | private static JsonWriter static_writer; |
130 | private static readonly object static_writer_lock = new Object (); |
131 | #endregion |
132 | |
133 | |
134 | #region Constructors |
135 | static JsonMapper () |
136 | { |
137 | max_nesting_depth = 100; |
138 | |
139 | array_metadata = new Dictionary<Type, ArrayMetadata> (); |
140 | conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> (); |
141 | object_metadata = new Dictionary<Type, ObjectMetadata> (); |
142 | type_properties = new Dictionary<Type, |
143 | IList<PropertyMetadata>> (); |
144 | |
145 | static_writer = new JsonWriter (); |
146 | |
147 | datetime_format = DateTimeFormatInfo.InvariantInfo; |
148 | |
149 | base_exporters_table = new Dictionary<Type, ExporterFunc> (); |
150 | custom_exporters_table = new Dictionary<Type, ExporterFunc> (); |
151 | |
152 | base_importers_table = new Dictionary<Type, |
153 | IDictionary<Type, ImporterFunc>> (); |
154 | custom_importers_table = new Dictionary<Type, |
155 | IDictionary<Type, ImporterFunc>> (); |
156 | |
157 | RegisterBaseExporters (); |
158 | RegisterBaseImporters (); |
159 | } |
160 | #endregion |
161 | |
162 | |
163 | #region Private Methods |
164 | private static void AddArrayMetadata (Type type) |
165 | { |
166 | if (array_metadata.ContainsKey (type)) |
167 | return; |
168 | |
169 | ArrayMetadata data = new ArrayMetadata (); |
170 | |
171 | data.IsArray = type.IsArray; |
172 | |
173 | if (type.GetInterface ("System.Collections.IList") != null) |
174 | data.IsList = true; |
175 | |
176 | foreach (PropertyInfo p_info in type.GetProperties ()) { |
177 | if (p_info.Name != "Item") |
178 | continue; |
179 | |
180 | ParameterInfo[] parameters = p_info.GetIndexParameters (); |
181 | |
182 | if (parameters.Length != 1) |
183 | continue; |
184 | |
185 | if (parameters[0].ParameterType == typeof (int)) |
186 | data.ElementType = p_info.PropertyType; |
187 | } |
188 | |
189 | lock (array_metadata_lock) { |
190 | try { |
191 | array_metadata.Add (type, data); |
192 | } catch (ArgumentException) { |
193 | return; |
194 | } |
195 | } |
196 | } |
197 | |
198 | private static void AddObjectMetadata (Type type) |
199 | { |
200 | if (object_metadata.ContainsKey (type)) |
201 | return; |
202 | |
203 | ObjectMetadata data = new ObjectMetadata (); |
204 | |
205 | if (type.GetInterface ("System.Collections.IDictionary") != null) |
206 | data.IsDictionary = true; |
207 | |
208 | data.Properties = new Dictionary<string, PropertyMetadata> (); |
209 | |
210 | foreach (PropertyInfo p_info in type.GetProperties ()) { |
211 | if (p_info.Name == "Item") { |
212 | ParameterInfo[] parameters = p_info.GetIndexParameters (); |
213 | |
214 | if (parameters.Length != 1) |
215 | continue; |
216 | |
217 | if (parameters[0].ParameterType == typeof (string)) |
218 | data.ElementType = p_info.PropertyType; |
219 | |
220 | continue; |
221 | } |
222 | |
223 | PropertyMetadata p_data = new PropertyMetadata (); |
224 | p_data.Info = p_info; |
225 | p_data.Type = p_info.PropertyType; |
226 | |
227 | data.Properties.Add (p_info.Name, p_data); |
228 | } |
229 | |
230 | foreach (FieldInfo f_info in type.GetFields ()) { |
231 | PropertyMetadata p_data = new PropertyMetadata (); |
232 | p_data.Info = f_info; |
233 | p_data.IsField = true; |
234 | p_data.Type = f_info.FieldType; |
235 | |
236 | data.Properties.Add (f_info.Name, p_data); |
237 | } |
238 | |
239 | lock (object_metadata_lock) { |
240 | try { |
241 | object_metadata.Add (type, data); |
242 | } catch (ArgumentException) { |
243 | return; |
244 | } |
245 | } |
246 | } |
247 | |
248 | private static void AddTypeProperties (Type type) |
249 | { |
250 | if (type_properties.ContainsKey (type)) |
251 | return; |
252 | |
253 | IList<PropertyMetadata> props = new List<PropertyMetadata> (); |
254 | |
255 | foreach (PropertyInfo p_info in type.GetProperties ()) { |
256 | if (p_info.Name == "Item") |
257 | continue; |
258 | |
259 | PropertyMetadata p_data = new PropertyMetadata (); |
260 | p_data.Info = p_info; |
261 | p_data.IsField = false; |
262 | props.Add (p_data); |
263 | } |
264 | |
265 | foreach (FieldInfo f_info in type.GetFields ()) { |
266 | PropertyMetadata p_data = new PropertyMetadata (); |
267 | p_data.Info = f_info; |
268 | p_data.IsField = true; |
269 | |
270 | props.Add (p_data); |
271 | } |
272 | |
273 | lock (type_properties_lock) { |
274 | try { |
275 | type_properties.Add (type, props); |
276 | } catch (ArgumentException) { |
277 | return; |
278 | } |
279 | } |
280 | } |
281 | |
282 | private static MethodInfo GetConvOp (Type t1, Type t2) |
283 | { |
284 | lock (conv_ops_lock) { |
285 | if (! conv_ops.ContainsKey (t1)) |
286 | conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ()); |
287 | } |
288 | |
289 | if (conv_ops[t1].ContainsKey (t2)) |
290 | return conv_ops[t1][t2]; |
291 | |
292 | MethodInfo op = t1.GetMethod ( |
293 | "op_Implicit", new Type[] { t2 }); |
294 | |
295 | lock (conv_ops_lock) { |
296 | try { |
297 | conv_ops[t1].Add (t2, op); |
298 | } catch (ArgumentException) { |
299 | return conv_ops[t1][t2]; |
300 | } |
301 | } |
302 | |
303 | return op; |
304 | } |
305 | |
306 | private static object ReadValue (Type inst_type, JsonReader reader) |
307 | { |
308 | reader.Read (); |
309 | |
310 | if (reader.Token == JsonToken.ArrayEnd) |
311 | return null; |
312 | |
313 | if (reader.Token == JsonToken.Null) { |
314 | |
315 | if (! inst_type.IsClass) |
316 | throw new JsonException (String.Format ( |
317 | "Can't assign null to an instance of type {0}", |
318 | inst_type)); |
319 | |
320 | return null; |
321 | } |
322 | |
323 | if (reader.Token == JsonToken.Double || |
324 | reader.Token == JsonToken.Int || |
325 | reader.Token == JsonToken.Long || |
326 | reader.Token == JsonToken.String || |
327 | reader.Token == JsonToken.Boolean) { |
328 | |
329 | Type json_type = reader.Value.GetType (); |
330 | |
331 | if (inst_type.IsAssignableFrom (json_type)) |
332 | return reader.Value; |
333 | |
334 | // If there's a custom importer that fits, use it |
335 | if (custom_importers_table.ContainsKey (json_type) && |
336 | custom_importers_table[json_type].ContainsKey ( |
337 | inst_type)) { |
338 | |
339 | ImporterFunc importer = |
340 | custom_importers_table[json_type][inst_type]; |
341 | |
342 | return importer (reader.Value); |
343 | } |
344 | |
345 | // Maybe there's a base importer that works |
346 | if (base_importers_table.ContainsKey (json_type) && |
347 | base_importers_table[json_type].ContainsKey ( |
348 | inst_type)) { |
349 | |
350 | ImporterFunc importer = |
351 | base_importers_table[json_type][inst_type]; |
352 | |
353 | return importer (reader.Value); |
354 | } |
355 | |
356 | // Maybe it's an enum |
357 | if (inst_type.IsEnum) |
358 | return Enum.ToObject (inst_type, reader.Value); |
359 | |
360 | // Try using an implicit conversion operator |
361 | MethodInfo conv_op = GetConvOp (inst_type, json_type); |
362 | |
363 | if (conv_op != null) |
364 | return conv_op.Invoke (null, |
365 | new object[] { reader.Value }); |
366 | |
367 | // No luck |
368 | throw new JsonException (String.Format ( |
369 | "Can't assign value '{0}' (type {1}) to type {2}", |
370 | reader.Value, json_type, inst_type)); |
371 | } |
372 | |
373 | object instance = null; |
374 | |
375 | if (reader.Token == JsonToken.ArrayStart) { |
376 | |
377 | AddArrayMetadata (inst_type); |
378 | ArrayMetadata t_data = array_metadata[inst_type]; |
379 | |
380 | if (! t_data.IsArray && ! t_data.IsList) |
381 | throw new JsonException (String.Format ( |
382 | "Type {0} can't act as an array", |
383 | inst_type)); |
384 | |
385 | IList list; |
386 | Type elem_type; |
387 | |
388 | if (! t_data.IsArray) { |
389 | list = (IList) Activator.CreateInstance (inst_type); |
390 | elem_type = t_data.ElementType; |
391 | } else { |
392 | list = new ArrayList (); |
393 | elem_type = inst_type.GetElementType (); |
394 | } |
395 | |
396 | while (true) { |
397 | object item = ReadValue (elem_type, reader); |
398 | if (item == null && reader.Token == JsonToken.ArrayEnd) |
399 | break; |
400 | |
401 | list.Add (item); |
402 | } |
403 | |
404 | if (t_data.IsArray) { |
405 | int n = list.Count; |
406 | instance = Array.CreateInstance (elem_type, n); |
407 | |
408 | for (int i = 0; i < n; i++) |
409 | ((Array) instance).SetValue (list[i], i); |
410 | } else |
411 | instance = list; |
412 | |
413 | } else if (reader.Token == JsonToken.ObjectStart) { |
414 | |
415 | AddObjectMetadata (inst_type); |
416 | ObjectMetadata t_data = object_metadata[inst_type]; |
417 | |
418 | instance = Activator.CreateInstance (inst_type); |
419 | |
420 | while (true) { |
421 | reader.Read (); |
422 | |
423 | if (reader.Token == JsonToken.ObjectEnd) |
424 | break; |
425 | |
426 | string property = (string) reader.Value; |
427 | |
428 | if (t_data.Properties.ContainsKey (property)) { |
429 | PropertyMetadata prop_data = |
430 | t_data.Properties[property]; |
431 | |
432 | if (prop_data.IsField) { |
433 | ((FieldInfo) prop_data.Info).SetValue ( |
434 | instance, ReadValue (prop_data.Type, reader)); |
435 | } else { |
436 | PropertyInfo p_info = |
437 | (PropertyInfo) prop_data.Info; |
438 | |
439 | if (p_info.CanWrite) |
440 | p_info.SetValue ( |
441 | instance, |
442 | ReadValue (prop_data.Type, reader), |
443 | null); |
444 | else |
445 | ReadValue (prop_data.Type, reader); |
446 | } |
447 | |
448 | } else { |
449 | if (! t_data.IsDictionary) { |
450 | |
451 | if (! reader.SkipNonMembers) { |
452 | throw new JsonException (String.Format ( |
453 | "The type {0} doesn't have the " + |
454 | "property '{1}'", |
455 | inst_type, property)); |
456 | } else { |
457 | ReadSkip (reader); |
458 | continue; |
459 | } |
460 | } |
461 | |
462 | ((IDictionary) instance).Add ( |
463 | property, ReadValue ( |
464 | t_data.ElementType, reader)); |
465 | } |
466 | |
467 | } |
468 | |
469 | } |
470 | |
471 | return instance; |
472 | } |
473 | |
474 | private static IJsonWrapper ReadValue (WrapperFactory factory, |
475 | JsonReader reader) |
476 | { |
477 | reader.Read (); |
478 | |
479 | if (reader.Token == JsonToken.ArrayEnd || |
480 | reader.Token == JsonToken.Null) |
481 | return null; |
482 | |
483 | IJsonWrapper instance = factory (); |
484 | |
485 | if (reader.Token == JsonToken.String) { |
486 | instance.SetString ((string) reader.Value); |
487 | return instance; |
488 | } |
489 | |
490 | if (reader.Token == JsonToken.Double) { |
491 | instance.SetDouble ((double) reader.Value); |
492 | return instance; |
493 | } |
494 | |
495 | if (reader.Token == JsonToken.Int) { |
496 | instance.SetInt ((int) reader.Value); |
497 | return instance; |
498 | } |
499 | |
500 | if (reader.Token == JsonToken.Long) { |
501 | instance.SetLong ((long) reader.Value); |
502 | return instance; |
503 | } |
504 | |
505 | if (reader.Token == JsonToken.Boolean) { |
506 | instance.SetBoolean ((bool) reader.Value); |
507 | return instance; |
508 | } |
509 | |
510 | if (reader.Token == JsonToken.ArrayStart) { |
511 | instance.SetJsonType (JsonType.Array); |
512 | |
513 | while (true) { |
514 | IJsonWrapper item = ReadValue (factory, reader); |
515 | if (item == null && reader.Token == JsonToken.ArrayEnd) |
516 | break; |
517 | |
518 | ((IList) instance).Add (item); |
519 | } |
520 | } |
521 | else if (reader.Token == JsonToken.ObjectStart) { |
522 | instance.SetJsonType (JsonType.Object); |
523 | |
524 | while (true) { |
525 | reader.Read (); |
526 | |
527 | if (reader.Token == JsonToken.ObjectEnd) |
528 | break; |
529 | |
530 | string property = (string) reader.Value; |
531 | |
532 | ((IDictionary) instance)[property] = ReadValue ( |
533 | factory, reader); |
534 | } |
535 | |
536 | } |
537 | |
538 | return instance; |
539 | } |
540 | |
541 | private static void ReadSkip (JsonReader reader) |
542 | { |
543 | ToWrapper ( |
544 | delegate { return new JsonMockWrapper (); }, reader); |
545 | } |
546 | |
547 | private static void RegisterBaseExporters () |
548 | { |
549 | base_exporters_table[typeof (byte)] = |
550 | delegate (object obj, JsonWriter writer) { |
551 | writer.Write (Convert.ToInt32 ((byte) obj)); |
552 | }; |
553 | |
554 | base_exporters_table[typeof (char)] = |
555 | delegate (object obj, JsonWriter writer) { |
556 | writer.Write (Convert.ToString ((char) obj)); |
557 | }; |
558 | |
559 | base_exporters_table[typeof (DateTime)] = |
560 | delegate (object obj, JsonWriter writer) { |
561 | writer.Write (Convert.ToString ((DateTime) obj, |
562 | datetime_format)); |
563 | }; |
564 | |
565 | base_exporters_table[typeof (decimal)] = |
566 | delegate (object obj, JsonWriter writer) { |
567 | writer.Write ((decimal) obj); |
568 | }; |
569 | |
570 | base_exporters_table[typeof (sbyte)] = |
571 | delegate (object obj, JsonWriter writer) { |
572 | writer.Write (Convert.ToInt32 ((sbyte) obj)); |
573 | }; |
574 | |
575 | base_exporters_table[typeof (short)] = |
576 | delegate (object obj, JsonWriter writer) { |
577 | writer.Write (Convert.ToInt32 ((short) obj)); |
578 | }; |
579 | |
580 | base_exporters_table[typeof (ushort)] = |
581 | delegate (object obj, JsonWriter writer) { |
582 | writer.Write (Convert.ToInt32 ((ushort) obj)); |
583 | }; |
584 | |
585 | base_exporters_table[typeof (uint)] = |
586 | delegate (object obj, JsonWriter writer) { |
587 | writer.Write (Convert.ToUInt64 ((uint) obj)); |
588 | }; |
589 | |
590 | base_exporters_table[typeof (ulong)] = |
591 | delegate (object obj, JsonWriter writer) { |
592 | writer.Write ((ulong) obj); |
593 | }; |
594 | } |
595 | |
596 | private static void RegisterBaseImporters () |
597 | { |
598 | ImporterFunc importer; |
599 | |
600 | importer = delegate (object input) { |
601 | return Convert.ToByte ((int) input); |
602 | }; |
603 | RegisterImporter (base_importers_table, typeof (int), |
604 | typeof (byte), importer); |
605 | |
606 | importer = delegate (object input) { |
607 | return Convert.ToUInt64 ((int) input); |
608 | }; |
609 | RegisterImporter (base_importers_table, typeof (int), |
610 | typeof (ulong), importer); |
611 | |
612 | importer = delegate (object input) { |
613 | return Convert.ToSByte ((int) input); |
614 | }; |
615 | RegisterImporter (base_importers_table, typeof (int), |
616 | typeof (sbyte), importer); |
617 | |
618 | importer = delegate (object input) { |
619 | return Convert.ToInt16 ((int) input); |
620 | }; |
621 | RegisterImporter (base_importers_table, typeof (int), |
622 | typeof (short), importer); |
623 | |
624 | importer = delegate (object input) { |
625 | return Convert.ToUInt16 ((int) input); |
626 | }; |
627 | RegisterImporter (base_importers_table, typeof (int), |
628 | typeof (ushort), importer); |
629 | |
630 | importer = delegate (object input) { |
631 | return Convert.ToUInt32 ((int) input); |
632 | }; |
633 | RegisterImporter (base_importers_table, typeof (int), |
634 | typeof (uint), importer); |
635 | |
636 | importer = delegate (object input) { |
637 | return Convert.ToSingle ((int) input); |
638 | }; |
639 | RegisterImporter (base_importers_table, typeof (int), |
640 | typeof (float), importer); |
641 | |
642 | importer = delegate (object input) { |
643 | return Convert.ToDouble ((int) input); |
644 | }; |
645 | RegisterImporter (base_importers_table, typeof (int), |
646 | typeof (double), importer); |
647 | |
648 | importer = delegate (object input) { |
649 | return Convert.ToDecimal ((double) input); |
650 | }; |
651 | RegisterImporter (base_importers_table, typeof (double), |
652 | typeof (decimal), importer); |
653 | |
654 | |
655 | importer = delegate (object input) { |
656 | return Convert.ToUInt32 ((long) input); |
657 | }; |
658 | RegisterImporter (base_importers_table, typeof (long), |
659 | typeof (uint), importer); |
660 | |
661 | importer = delegate (object input) { |
662 | return Convert.ToChar ((string) input); |
663 | }; |
664 | RegisterImporter (base_importers_table, typeof (string), |
665 | typeof (char), importer); |
666 | |
667 | importer = delegate (object input) { |
668 | return Convert.ToDateTime ((string) input, datetime_format); |
669 | }; |
670 | RegisterImporter (base_importers_table, typeof (string), |
671 | typeof (DateTime), importer); |
672 | } |
673 | |
674 | private static void RegisterImporter ( |
675 | IDictionary<Type, IDictionary<Type, ImporterFunc>> table, |
676 | Type json_type, Type value_type, ImporterFunc importer) |
677 | { |
678 | if (! table.ContainsKey (json_type)) |
679 | table.Add (json_type, new Dictionary<Type, ImporterFunc> ()); |
680 | |
681 | table[json_type][value_type] = importer; |
682 | } |
683 | |
684 | private static void WriteValue (object obj, JsonWriter writer, |
685 | bool writer_is_private, |
686 | int depth) |
687 | { |
688 | if (depth > max_nesting_depth) |
689 | throw new JsonException ( |
690 | String.Format ("Max allowed object depth reached while " + |
691 | "trying to export from type {0}", |
692 | obj.GetType ())); |
693 | |
694 | if (obj == null) { |
695 | writer.Write (null); |
696 | return; |
697 | } |
698 | |
699 | if (obj is IJsonWrapper) { |
700 | if (writer_is_private) |
701 | writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ()); |
702 | else |
703 | ((IJsonWrapper) obj).ToJson (writer); |
704 | |
705 | return; |
706 | } |
707 | |
708 | if (obj is String) { |
709 | writer.Write ((string) obj); |
710 | return; |
711 | } |
712 | |
713 | if (obj is Double) { |
714 | writer.Write ((double) obj); |
715 | return; |
716 | } |
717 | |
718 | if (obj is Int32) { |
719 | writer.Write ((int) obj); |
720 | return; |
721 | } |
722 | |
723 | if (obj is Boolean) { |
724 | writer.Write ((bool) obj); |
725 | return; |
726 | } |
727 | |
728 | if (obj is Int64) { |
729 | writer.Write ((long) obj); |
730 | return; |
731 | } |
732 | |
733 | if (obj is Array) { |
734 | writer.WriteArrayStart (); |
735 | |
736 | foreach (object elem in (Array) obj) |
737 | WriteValue (elem, writer, writer_is_private, depth + 1); |
738 | |
739 | writer.WriteArrayEnd (); |
740 | |
741 | return; |
742 | } |
743 | |
744 | if (obj is IList) { |
745 | writer.WriteArrayStart (); |
746 | foreach (object elem in (IList) obj) |
747 | WriteValue (elem, writer, writer_is_private, depth + 1); |
748 | writer.WriteArrayEnd (); |
749 | |
750 | return; |
751 | } |
752 | |
753 | if (obj is IDictionary) { |
754 | writer.WriteObjectStart (); |
755 | foreach (DictionaryEntry entry in (IDictionary) obj) { |
756 | writer.WritePropertyName ((string) entry.Key); |
757 | WriteValue (entry.Value, writer, writer_is_private, |
758 | depth + 1); |
759 | } |
760 | writer.WriteObjectEnd (); |
761 | |
762 | return; |
763 | } |
764 | |
765 | Type obj_type = obj.GetType (); |
766 | |
767 | // See if there's a custom exporter for the object |
768 | if (custom_exporters_table.ContainsKey (obj_type)) { |
769 | ExporterFunc exporter = custom_exporters_table[obj_type]; |
770 | exporter (obj, writer); |
771 | |
772 | return; |
773 | } |
774 | |
775 | // If not, maybe there's a base exporter |
776 | if (base_exporters_table.ContainsKey (obj_type)) { |
777 | ExporterFunc exporter = base_exporters_table[obj_type]; |
778 | exporter (obj, writer); |
779 | |
780 | return; |
781 | } |
782 | |
783 | // Last option, let's see if it's an enum |
784 | if (obj is Enum) { |
785 | Type e_type = Enum.GetUnderlyingType (obj_type); |
786 | |
787 | if (e_type == typeof (long) |
788 | || e_type == typeof (uint) |
789 | || e_type == typeof (ulong)) |
790 | writer.Write ((ulong) obj); |
791 | else |
792 | writer.Write ((int) obj); |
793 | |
794 | return; |
795 | } |
796 | |
797 | // Okay, so it looks like the input should be exported as an |
798 | // object |
799 | AddTypeProperties (obj_type); |
800 | IList<PropertyMetadata> props = type_properties[obj_type]; |
801 | |
802 | writer.WriteObjectStart (); |
803 | foreach (PropertyMetadata p_data in props) { |
804 | if (p_data.IsField) { |
805 | writer.WritePropertyName (p_data.Info.Name); |
806 | WriteValue (((FieldInfo) p_data.Info).GetValue (obj), |
807 | writer, writer_is_private, depth + 1); |
808 | } |
809 | else { |
810 | PropertyInfo p_info = (PropertyInfo) p_data.Info; |
811 | |
812 | if (p_info.CanRead) { |
813 | writer.WritePropertyName (p_data.Info.Name); |
814 | WriteValue (p_info.GetValue (obj, null), |
815 | writer, writer_is_private, depth + 1); |
816 | } |
817 | } |
818 | } |
819 | writer.WriteObjectEnd (); |
820 | } |
821 | #endregion |
822 | |
823 | |
824 | public static string ToJson (object obj) |
825 | { |
826 | lock (static_writer_lock) { |
827 | static_writer.Reset (); |
828 | |
829 | WriteValue (obj, static_writer, true, 0); |
830 | |
831 | return static_writer.ToString (); |
832 | } |
833 | } |
834 | |
835 | public static void ToJson (object obj, JsonWriter writer) |
836 | { |
837 | WriteValue (obj, writer, false, 0); |
838 | } |
839 | |
840 | public static JsonData ToObject (JsonReader reader) |
841 | { |
842 | return (JsonData) ToWrapper ( |
843 | delegate { return new JsonData (); }, reader); |
844 | } |
845 | |
846 | public static JsonData ToObject (TextReader reader) |
847 | { |
848 | JsonReader json_reader = new JsonReader (reader); |
849 | |
850 | return (JsonData) ToWrapper ( |
851 | delegate { return new JsonData (); }, json_reader); |
852 | } |
853 | |
854 | public static JsonData ToObject (string json) |
855 | { |
856 | return (JsonData) ToWrapper ( |
857 | delegate { return new JsonData (); }, json); |
858 | } |
859 | |
860 | public static T ToObject<T> (JsonReader reader) |
861 | { |
862 | return (T) ReadValue (typeof (T), reader); |
863 | } |
864 | |
865 | public static T ToObject<T> (TextReader reader) |
866 | { |
867 | JsonReader json_reader = new JsonReader (reader); |
868 | |
869 | return (T) ReadValue (typeof (T), json_reader); |
870 | } |
871 | |
872 | public static T ToObject<T> (string json) |
873 | { |
874 | JsonReader reader = new JsonReader (json); |
875 | |
876 | return (T) ReadValue (typeof (T), reader); |
877 | } |
878 | |
879 | public static IJsonWrapper ToWrapper (WrapperFactory factory, |
880 | JsonReader reader) |
881 | { |
882 | return ReadValue (factory, reader); |
883 | } |
884 | |
885 | public static IJsonWrapper ToWrapper (WrapperFactory factory, |
886 | string json) |
887 | { |
888 | JsonReader reader = new JsonReader (json); |
889 | |
890 | return ReadValue (factory, reader); |
891 | } |
892 | |
893 | public static void RegisterExporter<T> (ExporterFunc<T> exporter) |
894 | { |
895 | ExporterFunc exporter_wrapper = |
896 | delegate (object obj, JsonWriter writer) { |
897 | exporter ((T) obj, writer); |
898 | }; |
899 | |
900 | custom_exporters_table[typeof (T)] = exporter_wrapper; |
901 | } |
902 | |
903 | public static void RegisterImporter<TJson, TValue> ( |
904 | ImporterFunc<TJson, TValue> importer) |
905 | { |
906 | ImporterFunc importer_wrapper = |
907 | delegate (object input) { |
908 | return importer ((TJson) input); |
909 | }; |
910 | |
911 | RegisterImporter (custom_importers_table, typeof (TJson), |
912 | typeof (TValue), importer_wrapper); |
913 | } |
914 | |
915 | public static void UnregisterExporters () |
916 | { |
917 | custom_exporters_table.Clear (); |
918 | } |
919 | |
920 | public static void UnregisterImporters () |
921 | { |
922 | custom_importers_table.Clear (); |
923 | } |
924 | } |
925 | } |