JsonMapper.cs 32 KB

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