JsonSerializer.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. #if !SILVERLIGHT
  5. using System.Data;
  6. #endif
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Text;
  10. using System.Collections.Specialized;
  11. using Top.Api;
  12. using Top.Api.Util;
  13. using System.Reflection;
  14. using System.Xml.Serialization;
  15. namespace FastJSON
  16. {
  17. internal sealed class JSONSerializer
  18. {
  19. private StringBuilder _output = new StringBuilder();
  20. //private StringBuilder _before = new StringBuilder();
  21. private int _before;
  22. private int _MAX_DEPTH = 20;
  23. int _current_depth = 0;
  24. private Dictionary<string, int> _globalTypes = new Dictionary<string, int>();
  25. private Dictionary<object, int> _cirobj = new Dictionary<object, int>();
  26. private JSONParameters _params;
  27. private bool _useEscapedUnicode = false;
  28. internal JSONSerializer(JSONParameters param)
  29. {
  30. _params = param;
  31. _useEscapedUnicode = _params.UseEscapedUnicode;
  32. _MAX_DEPTH = _params.SerializerMaxDepth;
  33. }
  34. internal string ConvertToJSON(object obj)
  35. {
  36. WriteValue(obj);
  37. if (_params.UsingGlobalTypes && _globalTypes != null && _globalTypes.Count > 0)
  38. {
  39. var sb = new StringBuilder();
  40. sb.Append("\"$types\":{");
  41. var pendingSeparator = false;
  42. foreach (var kv in _globalTypes)
  43. {
  44. if (pendingSeparator) sb.Append(',');
  45. pendingSeparator = true;
  46. sb.Append('\"');
  47. sb.Append(kv.Key);
  48. sb.Append("\":\"");
  49. sb.Append(kv.Value);
  50. sb.Append('\"');
  51. }
  52. sb.Append("},");
  53. _output.Insert(_before, sb.ToString());
  54. }
  55. return _output.ToString();
  56. }
  57. private void WriteValue(object obj)
  58. {
  59. if (obj == null || obj is DBNull)
  60. _output.Append("null");
  61. else if (obj is string || obj is char)
  62. WriteString(obj.ToString());
  63. else if (obj is Guid)
  64. WriteGuid((Guid)obj);
  65. else if (obj is bool)
  66. _output.Append(((bool)obj) ? "true" : "false"); // conform to standard
  67. else if (
  68. obj is int || obj is long || obj is double ||
  69. obj is decimal || obj is float ||
  70. obj is byte || obj is short ||
  71. obj is sbyte || obj is ushort ||
  72. obj is uint || obj is ulong
  73. )
  74. _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo));
  75. else if (obj is DateTime)
  76. WriteDateTime((DateTime)obj);
  77. else if (_params.KVStyleStringDictionary == false && obj is IDictionary &&
  78. obj.GetType().IsGenericType && obj.GetType().GetGenericArguments()[0] == typeof(string))
  79. WriteStringDictionary((IDictionary)obj);
  80. #if net4
  81. else if (_params.KVStyleStringDictionary == false && obj is System.Dynamic.ExpandoObject)
  82. WriteStringDictionary((IDictionary<string, object>)obj);
  83. #endif
  84. else if (obj is IDictionary)
  85. WriteStringDictionary((IDictionary)obj);
  86. #if !SILVERLIGHT
  87. else if (obj is DataSet)
  88. WriteDataset((DataSet)obj);
  89. else if (obj is DataTable)
  90. this.WriteDataTable((DataTable)obj);
  91. #endif
  92. else if (obj is byte[])
  93. WriteBytes((byte[])obj);
  94. else if (obj is StringDictionary)
  95. WriteSD((StringDictionary)obj);
  96. else if (obj is NameValueCollection)
  97. WriteNV((NameValueCollection)obj);
  98. else if (obj is IEnumerable)
  99. WriteArray((IEnumerable)obj);
  100. else if (obj is Enum)
  101. WriteEnum((Enum)obj);
  102. else if (Reflection.Instance.IsTypeRegistered(obj.GetType()))
  103. WriteCustom(obj);
  104. else
  105. WriteObject(obj);
  106. }
  107. private void WriteNV(NameValueCollection nameValueCollection)
  108. {
  109. _output.Append('{');
  110. bool pendingSeparator = false;
  111. foreach (string key in nameValueCollection)
  112. {
  113. if (_params.SerializeNullValues == false && (nameValueCollection[key] == null))
  114. {
  115. }
  116. else
  117. {
  118. if (pendingSeparator) _output.Append(',');
  119. if (_params.SerializeToLowerCaseNames)
  120. WritePair(key.ToLower(), nameValueCollection[key]);
  121. else
  122. WritePair(key, nameValueCollection[key]);
  123. pendingSeparator = true;
  124. }
  125. }
  126. _output.Append('}');
  127. }
  128. private void WriteSD(StringDictionary stringDictionary)
  129. {
  130. _output.Append('{');
  131. bool pendingSeparator = false;
  132. foreach (DictionaryEntry entry in stringDictionary)
  133. {
  134. if (_params.SerializeNullValues == false && (entry.Value == null))
  135. {
  136. }
  137. else
  138. {
  139. if (pendingSeparator) _output.Append(',');
  140. string k = (string)entry.Key;
  141. if (_params.SerializeToLowerCaseNames)
  142. WritePair(k.ToLower(), entry.Value);
  143. else
  144. WritePair(k, entry.Value);
  145. pendingSeparator = true;
  146. }
  147. }
  148. _output.Append('}');
  149. }
  150. private void WriteCustom(object obj)
  151. {
  152. Serialize s;
  153. Reflection.Instance._customSerializer.TryGetValue(obj.GetType(), out s);
  154. WriteStringFast(s(obj));
  155. }
  156. private void WriteEnum(Enum e)
  157. {
  158. // TODO : optimize enum write
  159. if (_params.UseValuesOfEnums)
  160. WriteValue(Convert.ToInt32(e));
  161. else
  162. WriteStringFast(e.ToString());
  163. }
  164. private void WriteGuid(Guid g)
  165. {
  166. if (_params.UseFastGuid == false)
  167. WriteStringFast(g.ToString());
  168. else
  169. WriteBytes(g.ToByteArray());
  170. }
  171. private void WriteBytes(byte[] bytes)
  172. {
  173. #if !SILVERLIGHT
  174. WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length, Base64FormattingOptions.None));
  175. #else
  176. WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length));
  177. #endif
  178. }
  179. private void WriteDateTime(DateTime dateTime)
  180. {
  181. if (_params.UseApiNamingStyle)
  182. {
  183. WriteString(dateTime.ToString(Constants.DATE_TIME_FORMAT));
  184. return;
  185. }
  186. // datetime format standard : yyyy-MM-dd HH:mm:ss
  187. DateTime dt = dateTime;
  188. if (_params.UseUTCDateTime)
  189. dt = dateTime.ToUniversalTime();
  190. _output.Append('\"');
  191. _output.Append(dt.Year.ToString("0000", NumberFormatInfo.InvariantInfo));
  192. _output.Append('-');
  193. _output.Append(dt.Month.ToString("00", NumberFormatInfo.InvariantInfo));
  194. _output.Append('-');
  195. _output.Append(dt.Day.ToString("00", NumberFormatInfo.InvariantInfo));
  196. _output.Append('T'); // strict ISO date compliance
  197. _output.Append(dt.Hour.ToString("00", NumberFormatInfo.InvariantInfo));
  198. _output.Append(':');
  199. _output.Append(dt.Minute.ToString("00", NumberFormatInfo.InvariantInfo));
  200. _output.Append(':');
  201. _output.Append(dt.Second.ToString("00", NumberFormatInfo.InvariantInfo));
  202. if (_params.DateTimeMilliseconds)
  203. {
  204. _output.Append('.');
  205. _output.Append(dt.Millisecond.ToString("000", NumberFormatInfo.InvariantInfo));
  206. }
  207. if (_params.UseUTCDateTime)
  208. _output.Append('Z');
  209. _output.Append('\"');
  210. }
  211. #if !SILVERLIGHT
  212. private DatasetSchema GetSchema(DataTable ds)
  213. {
  214. if (ds == null) return null;
  215. DatasetSchema m = new DatasetSchema();
  216. m.Info = new List<string>();
  217. m.Name = ds.TableName;
  218. foreach (DataColumn c in ds.Columns)
  219. {
  220. m.Info.Add(ds.TableName);
  221. m.Info.Add(c.ColumnName);
  222. m.Info.Add(c.DataType.ToString());
  223. }
  224. // FEATURE : serialize relations and constraints here
  225. return m;
  226. }
  227. private DatasetSchema GetSchema(DataSet ds)
  228. {
  229. if (ds == null) return null;
  230. DatasetSchema m = new DatasetSchema();
  231. m.Info = new List<string>();
  232. m.Name = ds.DataSetName;
  233. foreach (DataTable t in ds.Tables)
  234. {
  235. foreach (DataColumn c in t.Columns)
  236. {
  237. m.Info.Add(t.TableName);
  238. m.Info.Add(c.ColumnName);
  239. m.Info.Add(c.DataType.ToString());
  240. }
  241. }
  242. // FEATURE : serialize relations and constraints here
  243. return m;
  244. }
  245. private string GetXmlSchema(DataTable dt)
  246. {
  247. using (var writer = new StringWriter())
  248. {
  249. dt.WriteXmlSchema(writer);
  250. return dt.ToString();
  251. }
  252. }
  253. private void WriteDataset(DataSet ds)
  254. {
  255. _output.Append('{');
  256. if (_params.UseExtensions)
  257. {
  258. WritePair("$schema", _params.UseOptimizedDatasetSchema ? (object)GetSchema(ds) : ds.GetXmlSchema());
  259. _output.Append(',');
  260. }
  261. bool tablesep = false;
  262. foreach (DataTable table in ds.Tables)
  263. {
  264. if (tablesep) _output.Append(',');
  265. tablesep = true;
  266. WriteDataTableData(table);
  267. }
  268. // end dataset
  269. _output.Append('}');
  270. }
  271. private void WriteDataTableData(DataTable table)
  272. {
  273. _output.Append('\"');
  274. _output.Append(table.TableName);
  275. _output.Append("\":[");
  276. DataColumnCollection cols = table.Columns;
  277. bool rowseparator = false;
  278. foreach (DataRow row in table.Rows)
  279. {
  280. if (rowseparator) _output.Append(',');
  281. rowseparator = true;
  282. _output.Append('[');
  283. bool pendingSeperator = false;
  284. foreach (DataColumn column in cols)
  285. {
  286. if (pendingSeperator) _output.Append(',');
  287. WriteValue(row[column]);
  288. pendingSeperator = true;
  289. }
  290. _output.Append(']');
  291. }
  292. _output.Append(']');
  293. }
  294. void WriteDataTable(DataTable dt)
  295. {
  296. this._output.Append('{');
  297. if (_params.UseExtensions)
  298. {
  299. this.WritePair("$schema", _params.UseOptimizedDatasetSchema ? (object)this.GetSchema(dt) : this.GetXmlSchema(dt));
  300. this._output.Append(',');
  301. }
  302. WriteDataTableData(dt);
  303. // end datatable
  304. this._output.Append('}');
  305. }
  306. #endif
  307. bool _TypesWritten = false;
  308. private void WriteObject(object obj)
  309. {
  310. int i = 0;
  311. if (_cirobj.TryGetValue(obj, out i) == false)
  312. _cirobj.Add(obj, _cirobj.Count + 1);
  313. else
  314. {
  315. if (_current_depth > 0 && _params.InlineCircularReferences == false)
  316. {
  317. //_circular = true;
  318. _output.Append("{\"$i\":");
  319. _output.Append(i.ToString());
  320. _output.Append("}");
  321. return;
  322. }
  323. }
  324. if (_params.UsingGlobalTypes == false)
  325. _output.Append('{');
  326. else
  327. {
  328. if (_TypesWritten == false)
  329. {
  330. _output.Append('{');
  331. _before = _output.Length;
  332. //_output = new StringBuilder();
  333. }
  334. else
  335. _output.Append('{');
  336. }
  337. _TypesWritten = true;
  338. _current_depth++;
  339. if (_current_depth > _MAX_DEPTH)
  340. throw new Exception("Serializer encountered maximum depth of " + _MAX_DEPTH);
  341. Dictionary<string, string> map = new Dictionary<string, string>();
  342. Type t = obj.GetType();
  343. bool append = false;
  344. if (_params.UseExtensions)
  345. {
  346. if (_params.UsingGlobalTypes == false)
  347. WritePairFast("$type", Reflection.Instance.GetTypeAssemblyName(t));
  348. else
  349. {
  350. int dt = 0;
  351. string ct = Reflection.Instance.GetTypeAssemblyName(t);
  352. if (_globalTypes.TryGetValue(ct, out dt) == false)
  353. {
  354. dt = _globalTypes.Count + 1;
  355. _globalTypes.Add(ct, dt);
  356. }
  357. WritePairFast("$type", dt.ToString());
  358. }
  359. append = true;
  360. }
  361. Getters[] g = Reflection.Instance.GetGetters(t, _params.ShowReadOnlyProperties, _params.IgnoreAttributes);
  362. int c = g.Length;
  363. for (int ii = 0; ii < c; ii++)
  364. {
  365. var p = g[ii];
  366. object o = p.Getter(obj);
  367. String itemName = null;
  368. PropertyInfo pi = t.GetProperty(p.Name);
  369. XmlElementAttribute[] xeas = pi.GetCustomAttributes(typeof(XmlElementAttribute), true) as XmlElementAttribute[];
  370. if (xeas != null && xeas.Length > 0)
  371. {
  372. itemName = xeas[0].ElementName;
  373. }
  374. // 获取列表属性名称
  375. if (itemName == null)
  376. {
  377. XmlArrayAttribute[] xaas = pi.GetCustomAttributes(typeof(XmlArrayAttribute), true) as XmlArrayAttribute[];
  378. if (xaas != null && xaas.Length > 0)
  379. {
  380. itemName = xaas[0].ElementName;
  381. }
  382. }
  383. if (_params.SerializeNullValues == false && (o == null || o is DBNull))
  384. {
  385. //append = false;
  386. }
  387. else
  388. {
  389. if (append)
  390. _output.Append(',');
  391. if (_params.SerializeToLowerCaseNames)
  392. WritePair(p.lcName, o, itemName);
  393. else
  394. WritePair(p.Name, o, itemName);
  395. if (o != null && _params.UseExtensions)
  396. {
  397. Type tt = o.GetType();
  398. if (tt == typeof(System.Object))
  399. map.Add(p.Name, tt.ToString());
  400. }
  401. append = true;
  402. }
  403. }
  404. if (map.Count > 0 && _params.UseExtensions)
  405. {
  406. _output.Append(",\"$map\":");
  407. WriteStringDictionary(map);
  408. }
  409. _output.Append('}');
  410. _current_depth--;
  411. }
  412. private void WritePairFast(string name, string value)
  413. {
  414. if (_params.UseApiNamingStyle)
  415. {
  416. string newName = StringUtil.ToUnderlineStyle(name.TrimEnd('_'));
  417. WriteStringFast(newName);
  418. }
  419. else
  420. {
  421. WriteStringFast(name);
  422. }
  423. _output.Append(':');
  424. WriteStringFast(value);
  425. }
  426. private void WritePair(string name, object value)
  427. {
  428. WritePair(name, value, null);
  429. }
  430. private void WritePair(string name, object value, String defaultName)
  431. {
  432. if (_params.UseApiNamingStyle)
  433. {
  434. if(defaultName != null)
  435. {
  436. WriteStringFast(defaultName);
  437. }
  438. else
  439. {
  440. string newName = StringUtil.ToUnderlineStyle(name.TrimEnd('_'));
  441. WriteStringFast(newName);
  442. }
  443. }
  444. else
  445. {
  446. WriteStringFast(name);
  447. }
  448. _output.Append(':');
  449. WriteValue(value);
  450. }
  451. private void WriteArray(IEnumerable array)
  452. {
  453. _output.Append('[');
  454. bool pendingSeperator = false;
  455. foreach (object obj in array)
  456. {
  457. if (pendingSeperator) _output.Append(',');
  458. WriteValue(obj);
  459. pendingSeperator = true;
  460. }
  461. _output.Append(']');
  462. }
  463. private void WriteStringDictionary(IDictionary dic)
  464. {
  465. _output.Append('{');
  466. bool pendingSeparator = false;
  467. foreach (DictionaryEntry entry in dic)
  468. {
  469. if (_params.SerializeNullValues == false && (entry.Value == null))
  470. {
  471. }
  472. else
  473. {
  474. if (pendingSeparator) _output.Append(',');
  475. string k = (string)entry.Key;
  476. if (_params.SerializeToLowerCaseNames)
  477. WritePair(k.ToLower(), entry.Value);
  478. else
  479. WritePair(k, entry.Value);
  480. pendingSeparator = true;
  481. }
  482. }
  483. _output.Append('}');
  484. }
  485. private void WriteStringDictionary(IDictionary<string, object> dic)
  486. {
  487. _output.Append('{');
  488. bool pendingSeparator = false;
  489. foreach (KeyValuePair<string, object> entry in dic)
  490. {
  491. if (_params.SerializeNullValues == false && (entry.Value == null))
  492. {
  493. }
  494. else
  495. {
  496. if (pendingSeparator) _output.Append(',');
  497. string k = entry.Key;
  498. if (_params.SerializeToLowerCaseNames)
  499. WritePair(k.ToLower(), entry.Value);
  500. else
  501. WritePair(k, entry.Value);
  502. pendingSeparator = true;
  503. }
  504. }
  505. _output.Append('}');
  506. }
  507. private void WriteDictionary(IDictionary dic)
  508. {
  509. _output.Append('[');
  510. bool pendingSeparator = false;
  511. foreach (DictionaryEntry entry in dic)
  512. {
  513. if (pendingSeparator) _output.Append(',');
  514. _output.Append('{');
  515. WritePair("k", entry.Key);
  516. _output.Append(",");
  517. WritePair("v", entry.Value);
  518. _output.Append('}');
  519. pendingSeparator = true;
  520. }
  521. _output.Append(']');
  522. }
  523. private void WriteStringFast(string s)
  524. {
  525. _output.Append('\"');
  526. _output.Append(s);
  527. _output.Append('\"');
  528. }
  529. private void WriteString(string s)
  530. {
  531. _output.Append('\"');
  532. int runIndex = -1;
  533. int l = s.Length;
  534. for (var index = 0; index < l; ++index)
  535. {
  536. var c = s[index];
  537. if (_useEscapedUnicode)
  538. {
  539. if (c >= ' ' && c < 128 && c != '\"' && c != '\\')
  540. {
  541. if (runIndex == -1)
  542. runIndex = index;
  543. continue;
  544. }
  545. }
  546. else
  547. {
  548. if (c != '\t' && c != '\n' && c != '\r' && c != '\"' && c != '\\')// && c != ':' && c!=',')
  549. {
  550. if (runIndex == -1)
  551. runIndex = index;
  552. continue;
  553. }
  554. }
  555. if (runIndex != -1)
  556. {
  557. _output.Append(s, runIndex, index - runIndex);
  558. runIndex = -1;
  559. }
  560. switch (c)
  561. {
  562. case '\t': _output.Append("\\t"); break;
  563. case '\r': _output.Append("\\r"); break;
  564. case '\n': _output.Append("\\n"); break;
  565. case '"':
  566. case '\\': _output.Append('\\'); _output.Append(c); break;
  567. default:
  568. if (_useEscapedUnicode)
  569. {
  570. _output.Append("\\u");
  571. _output.Append(((int)c).ToString("X4", NumberFormatInfo.InvariantInfo));
  572. }
  573. else
  574. _output.Append(c);
  575. break;
  576. }
  577. }
  578. if (runIndex != -1)
  579. _output.Append(s, runIndex, s.Length - runIndex);
  580. _output.Append('\"');
  581. }
  582. }
  583. }