Statistics
| Branch: | Tag: | Revision:

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
}